frontend 0.4.0

rustc's frontend with no LLVM and no std: parsing through MIR, as a library
//! Computes a projection goal for inherent associated types,
//! `#![feature(inherent_associated_type)]`. Since HIR ty lowering already determines
//! which impl the IAT is being projected from, we just:
//! 1. instantiate generic parameters,
//! 2. equate the self type, and
//! 3. instantiate and register where clauses.

use crate::rustc_type_ir::solve::QueryResultOrRerunNonErased;
use crate::rustc_type_ir::{self as ty, Interner, Unnormalized};

use crate::rustc_next_trait_solver::delegate::SolverDelegate;
use crate::rustc_next_trait_solver::solve::{Certainty, EvalCtxt, Goal, GoalSource};

impl<D, I> EvalCtxt<'_, D>
where
    D: SolverDelegate<Interner = I>,
    I: Interner,
{
    pub(super) fn normalize_inherent_associated_term(
        &mut self,
        goal: Goal<I, ty::ProjectionClause<I>>,
    ) -> QueryResultOrRerunNonErased<I> {
        let cx = self.cx();
        let inherent = goal.predicate.projection_term;
        let def_id = inherent.expect_inherent_def_id();
        let impl_def_id = cx.inherent_alias_term_parent(def_id);
        let impl_args = self.fresh_args_for_item(impl_def_id.into());

        // Equate impl header and add impl where clauses
        self.eq(
            goal.param_env,
            inherent.self_ty(),
            cx.type_of(impl_def_id.into()).instantiate(cx, impl_args).skip_norm_wip(),
        )?;

        // Equate IAT with the RHS of the project goal
        let inherent_args = inherent.rebase_inherent_args_onto_impl(impl_args, cx);

        // Check both where clauses on the impl and IAT
        //
        // FIXME(-Znext-solver=coinductive): I think this should be split
        // and we tag the impl bounds with `GoalSource::ImplWhereBound`?
        // Right now this includes both the impl and the assoc item where bounds,
        // and I don't think the assoc item where-bounds are allowed to be coinductive.
        //
        // Projecting to the IAT also "steps out the impl constructor", so we would have
        // to be very careful when changing the impl where-clauses to be productive.
        self.add_goals(
            GoalSource::Misc,
            cx.clauses_of(def_id.into())
                .iter_instantiated(cx, inherent_args)
                .map(Unnormalized::skip_norm_wip)
                .map(|clause| goal.with(cx, clause)),
        )?;

        let normalized: I::Term = match inherent.kind {
            ty::AliasTermKind::InherentTy { def_id } => {
                let inherent = cx.type_of(def_id.into()).instantiate(cx, inherent_args);
                let inherent = self.normalize(GoalSource::Misc, goal.param_env, inherent)?;
                inherent.into()
            }
            ty::AliasTermKind::InherentConst { def_id } if cx.is_type_const(def_id.into()) => {
                let inherent = cx.const_of_item(def_id.into()).instantiate(cx, inherent_args);
                let inherent = self.normalize(GoalSource::Misc, goal.param_env, inherent)?;
                inherent.into()
            }
            ty::AliasTermKind::InherentConst { .. } => {
                // FIXME(gca): This is dead code at the moment. It should eventually call
                // self.evaluate_const like projected consts do in consider_impl_candidate in
                // normalizes_to/mod.rs. However, how generic args are represented for IACs is up in
                // the air right now.
                // Will self.evaluate_const eventually take the inherent_args or the impl_args form
                // of args? It might be either.
                panic!("References to inherent associated consts should have been blocked");
            }
            kind => panic!("expected inherent alias, found {kind:?}"),
        };

        self.push_const_arg_has_type_goal(
            goal.param_env,
            goal.predicate.projection_term,
            normalized,
        )?;
        self.eq(goal.param_env, goal.predicate.term, normalized)?;
        self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
    }
}