Skip to main content

rustc_next_trait_solver/solve/project_goals/
inherent.rs

1//! Computes a projection goal for inherent associated types,
2//! `#![feature(inherent_associated_type)]`. Since HIR ty lowering already determines
3//! which impl the IAT is being projected from, we just:
4//! 1. instantiate generic parameters,
5//! 2. equate the self type, and
6//! 3. instantiate and register where clauses.
7
8use rustc_type_ir::solve::{NoSolutionOrRerunNonErased, QueryResultOrRerunNonErased};
9use rustc_type_ir::{self as ty, Interner, Unnormalized};
10
11use crate::delegate::SolverDelegate;
12use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource};
13
14impl<D, I> EvalCtxt<'_, D>
15where
16    D: SolverDelegate<Interner = I>,
17    I: Interner,
18{
19    pub(super) fn normalize_inherent_associated_term(
20        &mut self,
21        goal: Goal<I, ty::ProjectionClause<I>>,
22    ) -> QueryResultOrRerunNonErased<I> {
23        let cx = self.cx();
24        let def_id = goal.predicate.projection_term.expect_inherent_def_id();
25        let (inherent_kind, inherent_args) =
26            self.convert_inherent_self_to_impl(goal.param_env, goal.predicate.projection_term)?;
27
28        // Check both where clauses on the impl and IAT
29        //
30        // FIXME(-Znext-solver=coinductive): I think this should be split
31        // and we tag the impl bounds with `GoalSource::ImplWhereBound`?
32        // Right now this includes both the impl and the assoc item where bounds,
33        // and I don't think the assoc item where-bounds are allowed to be coinductive.
34        //
35        // Projecting to the IAT also "steps out the impl constructor", so we would have
36        // to be very careful when changing the impl where-clauses to be productive.
37        self.add_goals(
38            GoalSource::Misc,
39            cx.clauses_of(def_id.into())
40                .iter_instantiated(cx, inherent_args)
41                .map(Unnormalized::skip_norm_wip)
42                .map(|clause| goal.with(cx, clause)),
43        )?;
44
45        let normalized: I::Term = match inherent_kind {
46            ty::AliasTermKind::InherentTy { def_id } => {
47                let inherent = cx.type_of(def_id.into()).instantiate(cx, inherent_args);
48                let inherent = self.normalize(GoalSource::Misc, goal.param_env, inherent)?;
49                inherent.into()
50            }
51            ty::AliasTermKind::InherentConstImpl { def_id }
52                if let Some(inherent) =
53                    cx.const_of_item(ty::AliasConstKind::InherentImpl { def_id }) =>
54            {
55                let inherent = inherent.instantiate(cx, inherent_args);
56                let normalized_ct = self.normalize(GoalSource::Misc, goal.param_env, inherent)?;
57                let normalized = normalized_ct.into();
58                let term = ty::AliasTerm::new_from_args(cx, inherent_kind, inherent_args);
59                self.push_const_arg_has_type_goal(goal.param_env, term, normalized)?;
60                normalized
61            }
62            ty::AliasTermKind::InherentConstImpl { .. } => {
63                let term = ty::AliasTerm::new_from_args(cx, inherent_kind, inherent_args);
64                // NOTE: we intentionally pass in the `InherentConstImpl` form as the term to
65                // instantiate to upon too-generic CTFE failure, as we ought to consistently compare
66                // identities via `InherentConstImpl` rather than `InherentConstSelf`.
67                return self.evaluate_const_and_instantiate_projection_term(
68                    goal.param_env,
69                    term,
70                    goal.predicate.term,
71                    term.expect_ct(),
72                );
73            }
74            kind => {
    ::core::panicking::panic_fmt(format_args!("expected inherent alias, found {0:?}",
            kind));
}panic!("expected inherent alias, found {kind:?}"),
75        };
76
77        self.eq(goal.param_env, goal.predicate.term, normalized)?;
78        self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
79    }
80
81    fn convert_inherent_self_to_impl(
82        &mut self,
83        param_env: I::ParamEnv,
84        term: ty::AliasTerm<I>,
85    ) -> Result<(ty::AliasTermKind<I>, I::GenericArgs), NoSolutionOrRerunNonErased> {
86        match term.kind {
87            ty::AliasTermKind::InherentTy { .. } | ty::AliasTermKind::InherentConstSelf { .. } => {
88                let cx = self.cx();
89                let def_id = term.expect_inherent_def_id();
90                let impl_def_id = cx.inherent_alias_term_parent(def_id);
91                let impl_args = self.fresh_args_for_item(impl_def_id.into());
92
93                // Equate impl header and add impl where clauses
94                self.eq(
95                    param_env,
96                    term.self_ty(),
97                    cx.type_of(impl_def_id.into()).instantiate(cx, impl_args).skip_norm_wip(),
98                )?;
99
100                // Equate IAT with the RHS of the project goal
101                let inherent_args = term.rebase_inherent_args_onto_impl(impl_args, cx);
102
103                let kind = match term.kind {
104                    ty::AliasTermKind::InherentTy { def_id } => {
105                        ty::AliasTermKind::InherentTy { def_id }
106                    }
107                    ty::AliasTermKind::InherentConstSelf { def_id } => {
108                        ty::AliasTermKind::InherentConstImpl { def_id }
109                    }
110                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
111                };
112
113                Ok((kind, inherent_args))
114            }
115            ty::AliasTermKind::InherentConstImpl { .. } => Ok((term.kind, term.args)),
116            kind => {
    ::core::panicking::panic_fmt(format_args!("expected inherent alias, found {0:?}",
            kind));
}panic!("expected inherent alias, found {kind:?}"),
117        }
118    }
119}