rustc_next_trait_solver/solve/eval_ctxt/
mod.rs

1use std::mem;
2use std::ops::ControlFlow;
3
4#[cfg(feature = "nightly")]
5use rustc_macros::HashStable_NoContext;
6use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack};
7use rustc_type_ir::fast_reject::DeepRejectCtxt;
8use rustc_type_ir::inherent::*;
9use rustc_type_ir::relate::Relate;
10use rustc_type_ir::relate::solver_relating::RelateExt;
11use rustc_type_ir::search_graph::PathKind;
12use rustc_type_ir::{
13    self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable, TypeFolder,
14    TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
15    TypingMode,
16};
17use tracing::{debug, instrument, trace};
18
19use super::has_only_region_constraints;
20use crate::coherence;
21use crate::delegate::SolverDelegate;
22use crate::solve::inspect::{self, ProofTreeBuilder};
23use crate::solve::search_graph::SearchGraph;
24use crate::solve::{
25    CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalEvaluationKind,
26    GoalSource, GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput,
27    QueryResult,
28};
29
30pub(super) mod canonical;
31mod probe;
32
33/// The kind of goal we're currently proving.
34///
35/// This has effects on cycle handling handling and on how we compute
36/// query responses, see the variant descriptions for more info.
37#[derive(Debug, Copy, Clone)]
38enum CurrentGoalKind {
39    Misc,
40    /// We're proving an trait goal for a coinductive trait, either an auto trait or `Sized`.
41    ///
42    /// These are currently the only goals whose impl where-clauses are considered to be
43    /// productive steps.
44    CoinductiveTrait,
45    /// Unlike other goals, `NormalizesTo` goals act like functions with the expected term
46    /// always being fully unconstrained. This would weaken inference however, as the nested
47    /// goals never get the inference constraints from the actual normalized-to type.
48    ///
49    /// Because of this we return any ambiguous nested goals from `NormalizesTo` to the
50    /// caller when then adds these to its own context. The caller is always an `AliasRelate`
51    /// goal so this never leaks out of the solver.
52    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    /// The inference context that backs (mostly) inference and placeholder terms
77    /// instantiated while solving goals.
78    ///
79    /// NOTE: The `InferCtxt` that backs the `EvalCtxt` is intentionally private,
80    /// because the `InferCtxt` is much more general than `EvalCtxt`. Methods such
81    /// as  `take_registered_region_obligations` can mess up query responses,
82    /// using `At::normalize` is totally wrong, calling `evaluate_root_goal` can
83    /// cause coinductive unsoundness, etc.
84    ///
85    /// Methods that are generally of use for trait solving are *intentionally*
86    /// re-declared through the `EvalCtxt` below, often with cleaner signatures
87    /// since we don't care about things like `ObligationCause`s and `Span`s here.
88    /// If some `InferCtxt` method is missing, please first think defensively about
89    /// the method's compatibility with this solver, or if an existing one does
90    /// the job already.
91    delegate: &'a D,
92
93    /// The variable info for the `var_values`, only used to make an ambiguous response
94    /// with no constraints.
95    variables: I::CanonicalVarKinds,
96
97    /// What kind of goal we're currently computing, see the enum definition
98    /// for more info.
99    current_goal_kind: CurrentGoalKind,
100    pub(super) var_values: CanonicalVarValues<I>,
101
102    /// The highest universe index nameable by the caller.
103    ///
104    /// When we enter a new binder inside of the query we create new universes
105    /// which the caller cannot name. We have to be careful with variables from
106    /// these new universes when creating the query response.
107    ///
108    /// Both because these new universes can prevent us from reaching a fixpoint
109    /// if we have a coinductive cycle and because that's the only way we can return
110    /// new placeholders to the caller.
111    pub(super) max_input_universe: ty::UniverseIndex,
112    /// The opaque types from the canonical input. We only need to return opaque types
113    /// which have been added to the storage while evaluating this goal.
114    pub(super) initial_opaque_types_storage_num_entries:
115        <D::Infcx as InferCtxtLike>::OpaqueTypeStorageEntries,
116
117    pub(super) search_graph: &'a mut SearchGraph<D>,
118
119    nested_goals: Vec<(GoalSource, Goal<I, I::Predicate>, Option<GoalStalledOn<I>>)>,
120
121    pub(super) origin_span: I::Span,
122
123    // Has this `EvalCtxt` errored out with `NoSolution` in `try_evaluate_added_goals`?
124    //
125    // If so, then it can no longer be used to make a canonical query response,
126    // since subsequent calls to `try_evaluate_added_goals` have possibly dropped
127    // ambiguous goals. Instead, a probe needs to be introduced somewhere in the
128    // evaluation code.
129    tainted: Result<(), NoSolution>,
130
131    pub(super) inspect: ProofTreeBuilder<D>,
132}
133
134#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)]
135#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
136pub enum GenerateProofTree {
137    Yes,
138    No,
139}
140
141pub trait SolverDelegateEvalExt: SolverDelegate {
142    /// Evaluates a goal from **outside** of the trait solver.
143    ///
144    /// Using this while inside of the solver is wrong as it uses a new
145    /// search graph which would break cycle detection.
146    fn evaluate_root_goal(
147        &self,
148        goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
149        generate_proof_tree: GenerateProofTree,
150        span: <Self::Interner as Interner>::Span,
151        stalled_on: Option<GoalStalledOn<Self::Interner>>,
152    ) -> (
153        Result<GoalEvaluation<Self::Interner>, NoSolution>,
154        Option<inspect::GoalEvaluation<Self::Interner>>,
155    );
156
157    /// Check whether evaluating `goal` with a depth of `root_depth` may
158    /// succeed. This only returns `false` if the goal is guaranteed to
159    /// not hold. In case evaluation overflows and fails with ambiguity this
160    /// returns `true`.
161    ///
162    /// This is only intended to be used as a performance optimization
163    /// in coherence checking.
164    fn root_goal_may_hold_with_depth(
165        &self,
166        root_depth: usize,
167        goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
168    ) -> bool;
169
170    // FIXME: This is only exposed because we need to use it in `analyse.rs`
171    // which is not yet uplifted. Once that's done, we should remove this.
172    fn evaluate_root_goal_raw(
173        &self,
174        goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
175        generate_proof_tree: GenerateProofTree,
176        stalled_on: Option<GoalStalledOn<Self::Interner>>,
177    ) -> (
178        Result<
179            (NestedNormalizationGoals<Self::Interner>, GoalEvaluation<Self::Interner>),
180            NoSolution,
181        >,
182        Option<inspect::GoalEvaluation<Self::Interner>>,
183    );
184}
185
186impl<D, I> SolverDelegateEvalExt for D
187where
188    D: SolverDelegate<Interner = I>,
189    I: Interner,
190{
191    #[instrument(level = "debug", skip(self))]
192    fn evaluate_root_goal(
193        &self,
194        goal: Goal<I, I::Predicate>,
195        generate_proof_tree: GenerateProofTree,
196        span: I::Span,
197        stalled_on: Option<GoalStalledOn<I>>,
198    ) -> (Result<GoalEvaluation<I>, NoSolution>, Option<inspect::GoalEvaluation<I>>) {
199        EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, span, |ecx| {
200            ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on)
201        })
202    }
203
204    fn root_goal_may_hold_with_depth(
205        &self,
206        root_depth: usize,
207        goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
208    ) -> bool {
209        self.probe(|| {
210            EvalCtxt::enter_root(self, root_depth, GenerateProofTree::No, I::Span::dummy(), |ecx| {
211                ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, None)
212            })
213            .0
214        })
215        .is_ok()
216    }
217
218    #[instrument(level = "debug", skip(self))]
219    fn evaluate_root_goal_raw(
220        &self,
221        goal: Goal<I, I::Predicate>,
222        generate_proof_tree: GenerateProofTree,
223        stalled_on: Option<GoalStalledOn<I>>,
224    ) -> (
225        Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolution>,
226        Option<inspect::GoalEvaluation<I>>,
227    ) {
228        EvalCtxt::enter_root(
229            self,
230            self.cx().recursion_limit(),
231            generate_proof_tree,
232            I::Span::dummy(),
233            |ecx| {
234                ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on)
235            },
236        )
237    }
238}
239
240impl<'a, D, I> EvalCtxt<'a, D>
241where
242    D: SolverDelegate<Interner = I>,
243    I: Interner,
244{
245    pub(super) fn typing_mode(&self) -> TypingMode<I> {
246        self.delegate.typing_mode()
247    }
248
249    /// Computes the `PathKind` for the step from the current goal to the
250    /// nested goal required due to `source`.
251    ///
252    /// See #136824 for a more detailed reasoning for this behavior. We
253    /// consider cycles to be coinductive if they 'step into' a where-clause
254    /// of a coinductive trait. We will likely extend this function in the future
255    /// and will need to clearly document it in the rustc-dev-guide before
256    /// stabilization.
257    pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind {
258        match source {
259            // We treat these goals as unknown for now. It is likely that most miscellaneous
260            // nested goals will be converted to an inductive variant in the future.
261            //
262            // Having unknown cycles is always the safer option, as changing that to either
263            // succeed or hard error is backwards compatible. If we incorrectly treat a cycle
264            // as inductive even though it should not be, it may be unsound during coherence and
265            // fixing it may cause inference breakage or introduce ambiguity.
266            GoalSource::Misc => PathKind::Unknown,
267            GoalSource::NormalizeGoal(path_kind) => path_kind,
268            GoalSource::ImplWhereBound => match self.current_goal_kind {
269                // We currently only consider a cycle coinductive if it steps
270                // into a where-clause of a coinductive trait.
271                CurrentGoalKind::CoinductiveTrait => PathKind::Coinductive,
272                // While normalizing via an impl does step into a where-clause of
273                // an impl, accessing the associated item immediately steps out of
274                // it again. This means cycles/recursive calls are not guarded
275                // by impls used for normalization.
276                //
277                // See tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs
278                // for how this can go wrong.
279                CurrentGoalKind::NormalizesTo => PathKind::Inductive,
280                // We probably want to make all traits coinductive in the future,
281                // so we treat cycles involving where-clauses of not-yet coinductive
282                // traits as ambiguous for now.
283                CurrentGoalKind::Misc => PathKind::Unknown,
284            },
285            // Relating types is always unproductive. If we were to map proof trees to
286            // corecursive functions as explained in #136824, relating types never
287            // introduces a constructor which could cause the recursion to be guarded.
288            GoalSource::TypeRelating => PathKind::Inductive,
289            // Instantiating a higher ranked goal can never cause the recursion to be
290            // guarded and is therefore unproductive.
291            GoalSource::InstantiateHigherRanked => PathKind::Inductive,
292            // These goal sources are likely unproductive and can be changed to
293            // `PathKind::Inductive`. Keeping them as unknown until we're confident
294            // about this and have an example where it is necessary.
295            GoalSource::AliasBoundConstCondition | GoalSource::AliasWellFormed => PathKind::Unknown,
296        }
297    }
298
299    /// Creates a root evaluation context and search graph. This should only be
300    /// used from outside of any evaluation, and other methods should be preferred
301    /// over using this manually (such as [`SolverDelegateEvalExt::evaluate_root_goal`]).
302    pub(super) fn enter_root<R>(
303        delegate: &D,
304        root_depth: usize,
305        generate_proof_tree: GenerateProofTree,
306        origin_span: I::Span,
307        f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R,
308    ) -> (R, Option<inspect::GoalEvaluation<I>>) {
309        let mut search_graph = SearchGraph::new(root_depth);
310
311        let mut ecx = EvalCtxt {
312            delegate,
313            search_graph: &mut search_graph,
314            nested_goals: Default::default(),
315            inspect: ProofTreeBuilder::new_maybe_root(generate_proof_tree),
316
317            // Only relevant when canonicalizing the response,
318            // which we don't do within this evaluation context.
319            max_input_universe: ty::UniverseIndex::ROOT,
320            initial_opaque_types_storage_num_entries: Default::default(),
321            variables: Default::default(),
322            var_values: CanonicalVarValues::dummy(),
323            current_goal_kind: CurrentGoalKind::Misc,
324            origin_span,
325            tainted: Ok(()),
326        };
327        let result = f(&mut ecx);
328
329        let proof_tree = ecx.inspect.finalize();
330        assert!(
331            ecx.nested_goals.is_empty(),
332            "root `EvalCtxt` should not have any goals added to it"
333        );
334
335        assert!(search_graph.is_empty());
336        (result, proof_tree)
337    }
338
339    /// Creates a nested evaluation context that shares the same search graph as the
340    /// one passed in. This is suitable for evaluation, granted that the search graph
341    /// has had the nested goal recorded on its stack ([`SearchGraph::with_new_goal`]),
342    /// but it's preferable to use other methods that call this one rather than this
343    /// method directly.
344    ///
345    /// This function takes care of setting up the inference context, setting the anchor,
346    /// and registering opaques from the canonicalized input.
347    fn enter_canonical<R>(
348        cx: I,
349        search_graph: &'a mut SearchGraph<D>,
350        canonical_input: CanonicalInput<I>,
351        canonical_goal_evaluation: &mut ProofTreeBuilder<D>,
352        f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R,
353    ) -> R {
354        let (ref delegate, input, var_values) = D::build_with_canonical(cx, &canonical_input);
355
356        for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
357            let prev = delegate.register_hidden_type_in_storage(key, ty, I::Span::dummy());
358            // It may be possible that two entries in the opaque type storage end up
359            // with the same key after resolving contained inference variables.
360            //
361            // We could put them in the duplicate list but don't have to. The opaques we
362            // encounter here are already tracked in the caller, so there's no need to
363            // also store them here. We'd take them out when computing the query response
364            // and then discard them, as they're already present in the input.
365            //
366            // Ideally we'd drop duplicate opaque type definitions when computing
367            // the canonical input. This is more annoying to implement and may cause a
368            // perf regression, so we do it inside of the query for now.
369            if let Some(prev) = prev {
370                debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`");
371            }
372        }
373
374        let initial_opaque_types_storage_num_entries = delegate.opaque_types_storage_num_entries();
375        let mut ecx = EvalCtxt {
376            delegate,
377            variables: canonical_input.canonical.variables,
378            var_values,
379            current_goal_kind: CurrentGoalKind::from_query_input(cx, input),
380            max_input_universe: canonical_input.canonical.max_universe,
381            initial_opaque_types_storage_num_entries,
382            search_graph,
383            nested_goals: Default::default(),
384            origin_span: I::Span::dummy(),
385            tainted: Ok(()),
386            inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values),
387        };
388
389        let result = f(&mut ecx, input.goal);
390        ecx.inspect.probe_final_state(ecx.delegate, ecx.max_input_universe);
391        canonical_goal_evaluation.goal_evaluation_step(ecx.inspect);
392
393        // When creating a query response we clone the opaque type constraints
394        // instead of taking them. This would cause an ICE here, since we have
395        // assertions against dropping an `InferCtxt` without taking opaques.
396        // FIXME: Once we remove support for the old impl we can remove this.
397        // FIXME: Could we make `build_with_canonical` into `enter_with_canonical` and call this at the end?
398        delegate.reset_opaque_types();
399
400        result
401    }
402
403    /// The entry point of the solver.
404    ///
405    /// This function deals with (coinductive) cycles, overflow, and caching
406    /// and then calls [`EvalCtxt::compute_goal`] which contains the actual
407    /// logic of the solver.
408    ///
409    /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal]
410    /// if you're inside of the solver or [SolverDelegateEvalExt::evaluate_root_goal] if you're
411    /// outside of it.
412    #[instrument(level = "debug", skip(cx, search_graph, goal_evaluation), ret)]
413    fn evaluate_canonical_goal(
414        cx: I,
415        search_graph: &'a mut SearchGraph<D>,
416        canonical_input: CanonicalInput<I>,
417        step_kind_from_parent: PathKind,
418        goal_evaluation: &mut ProofTreeBuilder<D>,
419    ) -> QueryResult<I> {
420        let mut canonical_goal_evaluation =
421            goal_evaluation.new_canonical_goal_evaluation(canonical_input);
422
423        // Deal with overflow, caching, and coinduction.
424        //
425        // The actual solver logic happens in `ecx.compute_goal`.
426        let result = ensure_sufficient_stack(|| {
427            search_graph.with_new_goal(
428                cx,
429                canonical_input,
430                step_kind_from_parent,
431                &mut canonical_goal_evaluation,
432                |search_graph, canonical_goal_evaluation| {
433                    EvalCtxt::enter_canonical(
434                        cx,
435                        search_graph,
436                        canonical_input,
437                        canonical_goal_evaluation,
438                        |ecx, goal| {
439                            let result = ecx.compute_goal(goal);
440                            ecx.inspect.query_result(result);
441                            result
442                        },
443                    )
444                },
445            )
446        });
447
448        canonical_goal_evaluation.query_result(result);
449        goal_evaluation.canonical_goal_evaluation(canonical_goal_evaluation);
450        result
451    }
452
453    /// Recursively evaluates `goal`, returning whether any inference vars have
454    /// been constrained and the certainty of the result.
455    fn evaluate_goal(
456        &mut self,
457        goal_evaluation_kind: GoalEvaluationKind,
458        source: GoalSource,
459        goal: Goal<I, I::Predicate>,
460        stalled_on: Option<GoalStalledOn<I>>,
461    ) -> Result<GoalEvaluation<I>, NoSolution> {
462        let (normalization_nested_goals, goal_evaluation) =
463            self.evaluate_goal_raw(goal_evaluation_kind, source, goal, stalled_on)?;
464        assert!(normalization_nested_goals.is_empty());
465        Ok(goal_evaluation)
466    }
467
468    /// Recursively evaluates `goal`, returning the nested goals in case
469    /// the nested goal is a `NormalizesTo` goal.
470    ///
471    /// As all other goal kinds do not return any nested goals and
472    /// `NormalizesTo` is only used by `AliasRelate`, all other callsites
473    /// should use [`EvalCtxt::evaluate_goal`] which discards that empty
474    /// storage.
475    pub(super) fn evaluate_goal_raw(
476        &mut self,
477        goal_evaluation_kind: GoalEvaluationKind,
478        source: GoalSource,
479        goal: Goal<I, I::Predicate>,
480        stalled_on: Option<GoalStalledOn<I>>,
481    ) -> Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolution> {
482        // If we have run this goal before, and it was stalled, check that any of the goal's
483        // args have changed. Otherwise, we don't need to re-run the goal because it'll remain
484        // stalled, since it'll canonicalize the same way and evaluation is pure.
485        if let Some(stalled_on) = stalled_on {
486            if !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value))
487                && !self
488                    .delegate
489                    .opaque_types_storage_num_entries()
490                    .needs_reevaluation(stalled_on.num_opaques)
491            {
492                return Ok((
493                    NestedNormalizationGoals::empty(),
494                    GoalEvaluation {
495                        certainty: Certainty::Maybe(stalled_on.stalled_cause),
496                        has_changed: HasChanged::No,
497                        stalled_on: Some(stalled_on),
498                    },
499                ));
500            }
501        }
502
503        let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
504        let mut goal_evaluation =
505            self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
506        let canonical_response = EvalCtxt::evaluate_canonical_goal(
507            self.cx(),
508            self.search_graph,
509            canonical_goal,
510            self.step_kind_for_source(source),
511            &mut goal_evaluation,
512        );
513        let response = match canonical_response {
514            Err(e) => {
515                self.inspect.goal_evaluation(goal_evaluation);
516                return Err(e);
517            }
518            Ok(response) => response,
519        };
520
521        let has_changed =
522            if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No };
523
524        let (normalization_nested_goals, certainty) =
525            self.instantiate_and_apply_query_response(goal.param_env, &orig_values, response);
526        self.inspect.goal_evaluation(goal_evaluation);
527
528        // FIXME: We previously had an assert here that checked that recomputing
529        // a goal after applying its constraints did not change its response.
530        //
531        // This assert was removed as it did not hold for goals constraining
532        // an inference variable to a recursive alias, e.g. in
533        // tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs.
534        //
535        // Once we have decided on how to handle trait-system-refactor-initiative#75,
536        // we should re-add an assert here.
537
538        let stalled_on = match certainty {
539            Certainty::Yes => None,
540            Certainty::Maybe(stalled_cause) => match has_changed {
541                // FIXME: We could recompute a *new* set of stalled variables by walking
542                // through the orig values, resolving, and computing the root vars of anything
543                // that is not resolved. Only when *these* have changed is it meaningful
544                // to recompute this goal.
545                HasChanged::Yes => None,
546                HasChanged::No => {
547                    // Remove the unconstrained RHS arg, which is expected to have changed.
548                    let mut stalled_vars = orig_values;
549                    if let Some(normalizes_to) = goal.predicate.as_normalizes_to() {
550                        let normalizes_to = normalizes_to.skip_binder();
551                        let rhs_arg: I::GenericArg = normalizes_to.term.into();
552                        let idx = stalled_vars
553                            .iter()
554                            .rposition(|arg| *arg == rhs_arg)
555                            .expect("expected unconstrained arg");
556                        stalled_vars.swap_remove(idx);
557                    }
558
559                    Some(GoalStalledOn {
560                        num_opaques: canonical_goal
561                            .canonical
562                            .value
563                            .predefined_opaques_in_body
564                            .opaque_types
565                            .len(),
566                        stalled_vars,
567                        stalled_cause,
568                    })
569                }
570            },
571        };
572
573        Ok((normalization_nested_goals, GoalEvaluation { certainty, has_changed, stalled_on }))
574    }
575
576    fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
577        let Goal { param_env, predicate } = goal;
578        let kind = predicate.kind();
579        if let Some(kind) = kind.no_bound_vars() {
580            match kind {
581                ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
582                    self.compute_trait_goal(Goal { param_env, predicate }).map(|(r, _via)| r)
583                }
584                ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
585                    self.compute_host_effect_goal(Goal { param_env, predicate })
586                }
587                ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => {
588                    self.compute_projection_goal(Goal { param_env, predicate })
589                }
590                ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => {
591                    self.compute_type_outlives_goal(Goal { param_env, predicate })
592                }
593                ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => {
594                    self.compute_region_outlives_goal(Goal { param_env, predicate })
595                }
596                ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
597                    self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
598                }
599                ty::PredicateKind::Subtype(predicate) => {
600                    self.compute_subtype_goal(Goal { param_env, predicate })
601                }
602                ty::PredicateKind::Coerce(predicate) => {
603                    self.compute_coerce_goal(Goal { param_env, predicate })
604                }
605                ty::PredicateKind::DynCompatible(trait_def_id) => {
606                    self.compute_dyn_compatible_goal(trait_def_id)
607                }
608                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
609                    self.compute_well_formed_goal(Goal { param_env, predicate: term })
610                }
611                ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
612                    self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })
613                }
614                ty::PredicateKind::ConstEquate(_, _) => {
615                    panic!("ConstEquate should not be emitted when `-Znext-solver` is active")
616                }
617                ty::PredicateKind::NormalizesTo(predicate) => {
618                    self.compute_normalizes_to_goal(Goal { param_env, predicate })
619                }
620                ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self
621                    .compute_alias_relate_goal(Goal {
622                        param_env,
623                        predicate: (lhs, rhs, direction),
624                    }),
625                ty::PredicateKind::Ambiguous => {
626                    self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
627                }
628            }
629        } else {
630            self.enter_forall(kind, |ecx, kind| {
631                let goal = goal.with(ecx.cx(), ty::Binder::dummy(kind));
632                ecx.add_goal(GoalSource::InstantiateHigherRanked, goal);
633                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
634            })
635        }
636    }
637
638    // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning
639    // the certainty of all the goals.
640    #[instrument(level = "trace", skip(self))]
641    pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolution> {
642        let mut response = Ok(Certainty::overflow(false));
643        for _ in 0..FIXPOINT_STEP_LIMIT {
644            // FIXME: This match is a bit ugly, it might be nice to change the inspect
645            // stuff to use a closure instead. which should hopefully simplify this a bit.
646            match self.evaluate_added_goals_step() {
647                Ok(Some(cert)) => {
648                    response = Ok(cert);
649                    break;
650                }
651                Ok(None) => {}
652                Err(NoSolution) => {
653                    response = Err(NoSolution);
654                    break;
655                }
656            }
657        }
658
659        if response.is_err() {
660            self.tainted = Err(NoSolution);
661        }
662
663        response
664    }
665
666    /// Iterate over all added goals: returning `Ok(Some(_))` in case we can stop rerunning.
667    ///
668    /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`.
669    fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution> {
670        let cx = self.cx();
671        // If this loop did not result in any progress, what's our final certainty.
672        let mut unchanged_certainty = Some(Certainty::Yes);
673        for (source, goal, stalled_on) in mem::take(&mut self.nested_goals) {
674            if let Some(certainty) = self.delegate.compute_goal_fast_path(goal, self.origin_span) {
675                match certainty {
676                    Certainty::Yes => {}
677                    Certainty::Maybe(_) => {
678                        self.nested_goals.push((source, goal, None));
679                        unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty));
680                    }
681                }
682                continue;
683            }
684
685            // We treat normalizes-to goals specially here. In each iteration we take the
686            // RHS of the projection, replace it with a fresh inference variable, and only
687            // after evaluating that goal do we equate the fresh inference variable with the
688            // actual RHS of the predicate.
689            //
690            // This is both to improve caching, and to avoid using the RHS of the
691            // projection predicate to influence the normalizes-to candidate we select.
692            //
693            // Forgetting to replace the RHS with a fresh inference variable when we evaluate
694            // this goal results in an ICE.
695            if let Some(pred) = goal.predicate.as_normalizes_to() {
696                // We should never encounter higher-ranked normalizes-to goals.
697                let pred = pred.no_bound_vars().unwrap();
698                // Replace the goal with an unconstrained infer var, so the
699                // RHS does not affect projection candidate assembly.
700                let unconstrained_rhs = self.next_term_infer_of_kind(pred.term);
701                let unconstrained_goal =
702                    goal.with(cx, ty::NormalizesTo { alias: pred.alias, term: unconstrained_rhs });
703
704                let (
705                    NestedNormalizationGoals(nested_goals),
706                    GoalEvaluation { certainty, stalled_on, has_changed: _ },
707                ) = self.evaluate_goal_raw(
708                    GoalEvaluationKind::Nested,
709                    source,
710                    unconstrained_goal,
711                    stalled_on,
712                )?;
713                // Add the nested goals from normalization to our own nested goals.
714                trace!(?nested_goals);
715                self.nested_goals.extend(nested_goals.into_iter().map(|(s, g)| (s, g, None)));
716
717                // Finally, equate the goal's RHS with the unconstrained var.
718                //
719                // SUBTLE:
720                // We structurally relate aliases here. This is necessary
721                // as we otherwise emit a nested `AliasRelate` goal in case the
722                // returned term is a rigid alias, resulting in overflow.
723                //
724                // It is correct as both `goal.predicate.term` and `unconstrained_rhs`
725                // start out as an unconstrained inference variable so any aliases get
726                // fully normalized when instantiating it.
727                //
728                // FIXME: Strictly speaking this may be incomplete if the normalized-to
729                // type contains an ambiguous alias referencing bound regions. We should
730                // consider changing this to only use "shallow structural equality".
731                self.eq_structurally_relating_aliases(
732                    goal.param_env,
733                    pred.term,
734                    unconstrained_rhs,
735                )?;
736
737                // We only look at the `projection_ty` part here rather than
738                // looking at the "has changed" return from evaluate_goal,
739                // because we expect the `unconstrained_rhs` part of the predicate
740                // to have changed -- that means we actually normalized successfully!
741                // FIXME: Do we need to eagerly resolve here? Or should we check
742                // if the cache key has any changed vars?
743                let with_resolved_vars = self.resolve_vars_if_possible(goal);
744                if pred.alias != goal.predicate.as_normalizes_to().unwrap().skip_binder().alias {
745                    unchanged_certainty = None;
746                }
747
748                match certainty {
749                    Certainty::Yes => {}
750                    Certainty::Maybe(_) => {
751                        self.nested_goals.push((source, with_resolved_vars, stalled_on));
752                        unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty));
753                    }
754                }
755            } else {
756                let GoalEvaluation { certainty, has_changed, stalled_on } =
757                    self.evaluate_goal(GoalEvaluationKind::Nested, source, goal, stalled_on)?;
758                if has_changed == HasChanged::Yes {
759                    unchanged_certainty = None;
760                }
761
762                match certainty {
763                    Certainty::Yes => {}
764                    Certainty::Maybe(_) => {
765                        self.nested_goals.push((source, goal, stalled_on));
766                        unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty));
767                    }
768                }
769            }
770        }
771
772        Ok(unchanged_certainty)
773    }
774
775    /// Record impl args in the proof tree for later access by `InspectCandidate`.
776    pub(crate) fn record_impl_args(&mut self, impl_args: I::GenericArgs) {
777        self.inspect.record_impl_args(self.delegate, self.max_input_universe, impl_args)
778    }
779
780    pub(super) fn cx(&self) -> I {
781        self.delegate.cx()
782    }
783
784    #[instrument(level = "debug", skip(self))]
785    pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) {
786        goal.predicate =
787            goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, source, goal.param_env));
788        self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal);
789        self.nested_goals.push((source, goal, None));
790    }
791
792    #[instrument(level = "trace", skip(self, goals))]
793    pub(super) fn add_goals(
794        &mut self,
795        source: GoalSource,
796        goals: impl IntoIterator<Item = Goal<I, I::Predicate>>,
797    ) {
798        for goal in goals {
799            self.add_goal(source, goal);
800        }
801    }
802
803    pub(super) fn next_region_var(&mut self) -> I::Region {
804        let region = self.delegate.next_region_infer();
805        self.inspect.add_var_value(region);
806        region
807    }
808
809    pub(super) fn next_ty_infer(&mut self) -> I::Ty {
810        let ty = self.delegate.next_ty_infer();
811        self.inspect.add_var_value(ty);
812        ty
813    }
814
815    pub(super) fn next_const_infer(&mut self) -> I::Const {
816        let ct = self.delegate.next_const_infer();
817        self.inspect.add_var_value(ct);
818        ct
819    }
820
821    /// Returns a ty infer or a const infer depending on whether `kind` is a `Ty` or `Const`.
822    /// If `kind` is an integer inference variable this will still return a ty infer var.
823    pub(super) fn next_term_infer_of_kind(&mut self, term: I::Term) -> I::Term {
824        match term.kind() {
825            ty::TermKind::Ty(_) => self.next_ty_infer().into(),
826            ty::TermKind::Const(_) => self.next_const_infer().into(),
827        }
828    }
829
830    /// Is the projection predicate is of the form `exists<T> <Ty as Trait>::Assoc = T`.
831    ///
832    /// This is the case if the `term` does not occur in any other part of the predicate
833    /// and is able to name all other placeholder and inference variables.
834    #[instrument(level = "trace", skip(self), ret)]
835    pub(super) fn term_is_fully_unconstrained(&self, goal: Goal<I, ty::NormalizesTo<I>>) -> bool {
836        let universe_of_term = match goal.predicate.term.kind() {
837            ty::TermKind::Ty(ty) => {
838                if let ty::Infer(ty::TyVar(vid)) = ty.kind() {
839                    self.delegate.universe_of_ty(vid).unwrap()
840                } else {
841                    return false;
842                }
843            }
844            ty::TermKind::Const(ct) => {
845                if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
846                    self.delegate.universe_of_ct(vid).unwrap()
847                } else {
848                    return false;
849                }
850            }
851        };
852
853        struct ContainsTermOrNotNameable<'a, D: SolverDelegate<Interner = I>, I: Interner> {
854            term: I::Term,
855            universe_of_term: ty::UniverseIndex,
856            delegate: &'a D,
857            cache: HashSet<I::Ty>,
858        }
859
860        impl<D: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, D, I> {
861            fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> {
862                if self.universe_of_term.can_name(universe) {
863                    ControlFlow::Continue(())
864                } else {
865                    ControlFlow::Break(())
866                }
867            }
868        }
869
870        impl<D: SolverDelegate<Interner = I>, I: Interner> TypeVisitor<I>
871            for ContainsTermOrNotNameable<'_, D, I>
872        {
873            type Result = ControlFlow<()>;
874            fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
875                if self.cache.contains(&t) {
876                    return ControlFlow::Continue(());
877                }
878
879                match t.kind() {
880                    ty::Infer(ty::TyVar(vid)) => {
881                        if let ty::TermKind::Ty(term) = self.term.kind() {
882                            if let ty::Infer(ty::TyVar(term_vid)) = term.kind() {
883                                if self.delegate.root_ty_var(vid)
884                                    == self.delegate.root_ty_var(term_vid)
885                                {
886                                    return ControlFlow::Break(());
887                                }
888                            }
889                        }
890
891                        self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?;
892                    }
893                    ty::Placeholder(p) => self.check_nameable(p.universe())?,
894                    _ => {
895                        if t.has_non_region_infer() || t.has_placeholders() {
896                            t.super_visit_with(self)?
897                        }
898                    }
899                }
900
901                assert!(self.cache.insert(t));
902                ControlFlow::Continue(())
903            }
904
905            fn visit_const(&mut self, c: I::Const) -> Self::Result {
906                match c.kind() {
907                    ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
908                        if let ty::TermKind::Const(term) = self.term.kind() {
909                            if let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind()
910                            {
911                                if self.delegate.root_const_var(vid)
912                                    == self.delegate.root_const_var(term_vid)
913                                {
914                                    return ControlFlow::Break(());
915                                }
916                            }
917                        }
918
919                        self.check_nameable(self.delegate.universe_of_ct(vid).unwrap())
920                    }
921                    ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe()),
922                    _ => {
923                        if c.has_non_region_infer() || c.has_placeholders() {
924                            c.super_visit_with(self)
925                        } else {
926                            ControlFlow::Continue(())
927                        }
928                    }
929                }
930            }
931
932            fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result {
933                if p.has_non_region_infer() || p.has_placeholders() {
934                    p.super_visit_with(self)
935                } else {
936                    ControlFlow::Continue(())
937                }
938            }
939
940            fn visit_clauses(&mut self, c: I::Clauses) -> Self::Result {
941                if c.has_non_region_infer() || c.has_placeholders() {
942                    c.super_visit_with(self)
943                } else {
944                    ControlFlow::Continue(())
945                }
946            }
947        }
948
949        let mut visitor = ContainsTermOrNotNameable {
950            delegate: self.delegate,
951            universe_of_term,
952            term: goal.predicate.term,
953            cache: Default::default(),
954        };
955        goal.predicate.alias.visit_with(&mut visitor).is_continue()
956            && goal.param_env.visit_with(&mut visitor).is_continue()
957    }
958
959    #[instrument(level = "trace", skip(self, param_env), ret)]
960    pub(super) fn eq<T: Relate<I>>(
961        &mut self,
962        param_env: I::ParamEnv,
963        lhs: T,
964        rhs: T,
965    ) -> Result<(), NoSolution> {
966        self.relate(param_env, lhs, ty::Variance::Invariant, rhs)
967    }
968
969    /// This should be used when relating a rigid alias with another type.
970    ///
971    /// Normally we emit a nested `AliasRelate` when equating an inference
972    /// variable and an alias. This causes us to instead constrain the inference
973    /// variable to the alias without emitting a nested alias relate goals.
974    #[instrument(level = "trace", skip(self, param_env), ret)]
975    pub(super) fn relate_rigid_alias_non_alias(
976        &mut self,
977        param_env: I::ParamEnv,
978        alias: ty::AliasTerm<I>,
979        variance: ty::Variance,
980        term: I::Term,
981    ) -> Result<(), NoSolution> {
982        // NOTE: this check is purely an optimization, the structural eq would
983        // always fail if the term is not an inference variable.
984        if term.is_infer() {
985            let cx = self.cx();
986            // We need to relate `alias` to `term` treating only the outermost
987            // constructor as rigid, relating any contained generic arguments as
988            // normal. We do this by first structurally equating the `term`
989            // with the alias constructor instantiated with unconstrained infer vars,
990            // and then relate this with the whole `alias`.
991            //
992            // Alternatively we could modify `Equate` for this case by adding another
993            // variant to `StructurallyRelateAliases`.
994            let identity_args = self.fresh_args_for_item(alias.def_id);
995            let rigid_ctor = ty::AliasTerm::new_from_args(cx, alias.def_id, identity_args);
996            let ctor_term = rigid_ctor.to_term(cx);
997            let obligations = self.delegate.eq_structurally_relating_aliases(
998                param_env,
999                term,
1000                ctor_term,
1001                self.origin_span,
1002            )?;
1003            debug_assert!(obligations.is_empty());
1004            self.relate(param_env, alias, variance, rigid_ctor)
1005        } else {
1006            Err(NoSolution)
1007        }
1008    }
1009
1010    /// This sohuld only be used when we're either instantiating a previously
1011    /// unconstrained "return value" or when we're sure that all aliases in
1012    /// the types are rigid.
1013    #[instrument(level = "trace", skip(self, param_env), ret)]
1014    pub(super) fn eq_structurally_relating_aliases<T: Relate<I>>(
1015        &mut self,
1016        param_env: I::ParamEnv,
1017        lhs: T,
1018        rhs: T,
1019    ) -> Result<(), NoSolution> {
1020        let result = self.delegate.eq_structurally_relating_aliases(
1021            param_env,
1022            lhs,
1023            rhs,
1024            self.origin_span,
1025        )?;
1026        assert_eq!(result, vec![]);
1027        Ok(())
1028    }
1029
1030    #[instrument(level = "trace", skip(self, param_env), ret)]
1031    pub(super) fn sub<T: Relate<I>>(
1032        &mut self,
1033        param_env: I::ParamEnv,
1034        sub: T,
1035        sup: T,
1036    ) -> Result<(), NoSolution> {
1037        self.relate(param_env, sub, ty::Variance::Covariant, sup)
1038    }
1039
1040    #[instrument(level = "trace", skip(self, param_env), ret)]
1041    pub(super) fn relate<T: Relate<I>>(
1042        &mut self,
1043        param_env: I::ParamEnv,
1044        lhs: T,
1045        variance: ty::Variance,
1046        rhs: T,
1047    ) -> Result<(), NoSolution> {
1048        let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?;
1049        for &goal in goals.iter() {
1050            let source = match goal.predicate.kind().skip_binder() {
1051                ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {
1052                    GoalSource::TypeRelating
1053                }
1054                // FIXME(-Znext-solver=coinductive): should these WF goals also be unproductive?
1055                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => GoalSource::Misc,
1056                p => unreachable!("unexpected nested goal in `relate`: {p:?}"),
1057            };
1058            self.add_goal(source, goal);
1059        }
1060        Ok(())
1061    }
1062
1063    /// Equates two values returning the nested goals without adding them
1064    /// to the nested goals of the `EvalCtxt`.
1065    ///
1066    /// If possible, try using `eq` instead which automatically handles nested
1067    /// goals correctly.
1068    #[instrument(level = "trace", skip(self, param_env), ret)]
1069    pub(super) fn eq_and_get_goals<T: Relate<I>>(
1070        &self,
1071        param_env: I::ParamEnv,
1072        lhs: T,
1073        rhs: T,
1074    ) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {
1075        Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs, self.origin_span)?)
1076    }
1077
1078    pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(
1079        &self,
1080        value: ty::Binder<I, T>,
1081    ) -> T {
1082        self.delegate.instantiate_binder_with_infer(value)
1083    }
1084
1085    /// `enter_forall`, but takes `&mut self` and passes it back through the
1086    /// callback since it can't be aliased during the call.
1087    pub(super) fn enter_forall<T: TypeFoldable<I>, U>(
1088        &mut self,
1089        value: ty::Binder<I, T>,
1090        f: impl FnOnce(&mut Self, T) -> U,
1091    ) -> U {
1092        self.delegate.enter_forall(value, |value| f(self, value))
1093    }
1094
1095    pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
1096    where
1097        T: TypeFoldable<I>,
1098    {
1099        self.delegate.resolve_vars_if_possible(value)
1100    }
1101
1102    pub(super) fn eager_resolve_region(&self, r: I::Region) -> I::Region {
1103        if let ty::ReVar(vid) = r.kind() {
1104            self.delegate.opportunistic_resolve_lt_var(vid)
1105        } else {
1106            r
1107        }
1108    }
1109
1110    pub(super) fn fresh_args_for_item(&mut self, def_id: I::DefId) -> I::GenericArgs {
1111        let args = self.delegate.fresh_args_for_item(def_id);
1112        for arg in args.iter() {
1113            self.inspect.add_var_value(arg);
1114        }
1115        args
1116    }
1117
1118    pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) {
1119        self.delegate.register_ty_outlives(ty, lt, self.origin_span);
1120    }
1121
1122    pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) {
1123        // `'a: 'b` ==> `'b <= 'a`
1124        self.delegate.sub_regions(b, a, self.origin_span);
1125    }
1126
1127    /// Computes the list of goals required for `arg` to be well-formed
1128    pub(super) fn well_formed_goals(
1129        &self,
1130        param_env: I::ParamEnv,
1131        term: I::Term,
1132    ) -> Option<Vec<Goal<I, I::Predicate>>> {
1133        self.delegate.well_formed_goals(param_env, term)
1134    }
1135
1136    pub(super) fn trait_ref_is_knowable(
1137        &mut self,
1138        param_env: I::ParamEnv,
1139        trait_ref: ty::TraitRef<I>,
1140    ) -> Result<bool, NoSolution> {
1141        let delegate = self.delegate;
1142        let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty);
1143        coherence::trait_ref_is_knowable(&**delegate, trait_ref, lazily_normalize_ty)
1144            .map(|is_knowable| is_knowable.is_ok())
1145    }
1146
1147    pub(super) fn fetch_eligible_assoc_item(
1148        &self,
1149        goal_trait_ref: ty::TraitRef<I>,
1150        trait_assoc_def_id: I::DefId,
1151        impl_def_id: I::DefId,
1152    ) -> Result<Option<I::DefId>, I::ErrorGuaranteed> {
1153        self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id)
1154    }
1155
1156    pub(super) fn register_hidden_type_in_storage(
1157        &mut self,
1158        opaque_type_key: ty::OpaqueTypeKey<I>,
1159        hidden_ty: I::Ty,
1160    ) -> Option<I::Ty> {
1161        self.delegate.register_hidden_type_in_storage(opaque_type_key, hidden_ty, self.origin_span)
1162    }
1163
1164    pub(super) fn add_item_bounds_for_hidden_type(
1165        &mut self,
1166        opaque_def_id: I::DefId,
1167        opaque_args: I::GenericArgs,
1168        param_env: I::ParamEnv,
1169        hidden_ty: I::Ty,
1170    ) {
1171        let mut goals = Vec::new();
1172        self.delegate.add_item_bounds_for_hidden_type(
1173            opaque_def_id,
1174            opaque_args,
1175            param_env,
1176            hidden_ty,
1177            &mut goals,
1178        );
1179        self.add_goals(GoalSource::AliasWellFormed, goals);
1180    }
1181
1182    // Do something for each opaque/hidden pair defined with `def_id` in the
1183    // current inference context.
1184    pub(super) fn probe_existing_opaque_ty(
1185        &mut self,
1186        key: ty::OpaqueTypeKey<I>,
1187    ) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> {
1188        // We shouldn't have any duplicate entries when using
1189        // this function during `TypingMode::Analysis`.
1190        let duplicate_entries = self.delegate.clone_duplicate_opaque_types();
1191        assert!(duplicate_entries.is_empty(), "unexpected duplicates: {duplicate_entries:?}");
1192        let mut matching = self.delegate.clone_opaque_types_lookup_table().into_iter().filter(
1193            |(candidate_key, _)| {
1194                candidate_key.def_id == key.def_id
1195                    && DeepRejectCtxt::relate_rigid_rigid(self.cx())
1196                        .args_may_unify(candidate_key.args, key.args)
1197            },
1198        );
1199        let first = matching.next();
1200        let second = matching.next();
1201        assert_eq!(second, None);
1202        first
1203    }
1204
1205    // Try to evaluate a const, or return `None` if the const is too generic.
1206    // This doesn't mean the const isn't evaluatable, though, and should be treated
1207    // as an ambiguity rather than no-solution.
1208    pub(super) fn evaluate_const(
1209        &self,
1210        param_env: I::ParamEnv,
1211        uv: ty::UnevaluatedConst<I>,
1212    ) -> Option<I::Const> {
1213        self.delegate.evaluate_const(param_env, uv)
1214    }
1215
1216    pub(super) fn is_transmutable(
1217        &mut self,
1218        dst: I::Ty,
1219        src: I::Ty,
1220        assume: I::Const,
1221    ) -> Result<Certainty, NoSolution> {
1222        self.delegate.is_transmutable(dst, src, assume)
1223    }
1224}
1225
1226/// Eagerly replace aliases with inference variables, emitting `AliasRelate`
1227/// goals, used when adding goals to the `EvalCtxt`. We compute the
1228/// `AliasRelate` goals before evaluating the actual goal to get all the
1229/// constraints we can.
1230///
1231/// This is a performance optimization to more eagerly detect cycles during trait
1232/// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs.
1233///
1234/// The emitted goals get evaluated in the context of the parent goal; by
1235/// replacing aliases in nested goals we essentially pull the normalization out of
1236/// the nested goal. We want to treat the goal as if the normalization still happens
1237/// inside of the nested goal by inheriting the `step_kind` of the nested goal and
1238/// storing it in the `GoalSource` of the emitted `AliasRelate` goals.
1239/// This is necessary for tests/ui/sized/coinductive-1.rs to compile.
1240struct ReplaceAliasWithInfer<'me, 'a, D, I>
1241where
1242    D: SolverDelegate<Interner = I>,
1243    I: Interner,
1244{
1245    ecx: &'me mut EvalCtxt<'a, D>,
1246    param_env: I::ParamEnv,
1247    normalization_goal_source: GoalSource,
1248    cache: HashMap<I::Ty, I::Ty>,
1249}
1250
1251impl<'me, 'a, D, I> ReplaceAliasWithInfer<'me, 'a, D, I>
1252where
1253    D: SolverDelegate<Interner = I>,
1254    I: Interner,
1255{
1256    fn new(
1257        ecx: &'me mut EvalCtxt<'a, D>,
1258        for_goal_source: GoalSource,
1259        param_env: I::ParamEnv,
1260    ) -> Self {
1261        let step_kind = ecx.step_kind_for_source(for_goal_source);
1262        ReplaceAliasWithInfer {
1263            ecx,
1264            param_env,
1265            normalization_goal_source: GoalSource::NormalizeGoal(step_kind),
1266            cache: Default::default(),
1267        }
1268    }
1269}
1270
1271impl<D, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, D, I>
1272where
1273    D: SolverDelegate<Interner = I>,
1274    I: Interner,
1275{
1276    fn cx(&self) -> I {
1277        self.ecx.cx()
1278    }
1279
1280    fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
1281        match ty.kind() {
1282            ty::Alias(..) if !ty.has_escaping_bound_vars() => {
1283                let infer_ty = self.ecx.next_ty_infer();
1284                let normalizes_to = ty::PredicateKind::AliasRelate(
1285                    ty.into(),
1286                    infer_ty.into(),
1287                    ty::AliasRelationDirection::Equate,
1288                );
1289                self.ecx.add_goal(
1290                    self.normalization_goal_source,
1291                    Goal::new(self.cx(), self.param_env, normalizes_to),
1292                );
1293                infer_ty
1294            }
1295            _ => {
1296                if !ty.has_aliases() {
1297                    ty
1298                } else if let Some(&entry) = self.cache.get(&ty) {
1299                    return entry;
1300                } else {
1301                    let res = ty.super_fold_with(self);
1302                    assert!(self.cache.insert(ty, res).is_none());
1303                    res
1304                }
1305            }
1306        }
1307    }
1308
1309    fn fold_const(&mut self, ct: I::Const) -> I::Const {
1310        match ct.kind() {
1311            ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
1312                let infer_ct = self.ecx.next_const_infer();
1313                let normalizes_to = ty::PredicateKind::AliasRelate(
1314                    ct.into(),
1315                    infer_ct.into(),
1316                    ty::AliasRelationDirection::Equate,
1317                );
1318                self.ecx.add_goal(
1319                    self.normalization_goal_source,
1320                    Goal::new(self.cx(), self.param_env, normalizes_to),
1321                );
1322                infer_ct
1323            }
1324            _ => ct.super_fold_with(self),
1325        }
1326    }
1327
1328    fn fold_predicate(&mut self, predicate: I::Predicate) -> I::Predicate {
1329        if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate }
1330    }
1331}