Skip to main content

rustc_next_trait_solver/solve/project_goals/
mod.rs

1mod anon_const;
2mod free_alias;
3mod inherent;
4mod opaque_types;
5
6use rustc_type_ir::solve::QueryResultOrRerunNonErased;
7use rustc_type_ir::{self as ty, Interner, ProjectionPredicate};
8use tracing::{instrument, trace};
9
10use crate::delegate::SolverDelegate;
11use crate::solve::{
12    Certainty, EvalCtxt, Goal, GoalEvaluation, GoalSource, NestedNormalizationGoals,
13};
14
15impl<D, I> EvalCtxt<'_, D>
16where
17    D: SolverDelegate<Interner = I>,
18    I: Interner,
19{
20    x;#[instrument(level = "trace", skip(self), ret)]
21    pub(super) fn compute_projection_goal(
22        &mut self,
23        goal: Goal<I, ProjectionPredicate<I>>,
24    ) -> QueryResultOrRerunNonErased<I> {
25        match goal.predicate.projection_term.kind {
26            ty::AliasTermKind::ProjectionTy { .. } | ty::AliasTermKind::ProjectionConst { .. } => {
27                self.normalize_associated_term(goal)
28            }
29            ty::AliasTermKind::InherentTy { .. } | ty::AliasTermKind::InherentConst { .. } => {
30                self.normalize_inherent_associated_term(goal)
31            }
32            ty::AliasTermKind::OpaqueTy { .. } => self.normalize_opaque_type(goal),
33            ty::AliasTermKind::FreeTy { .. } | ty::AliasTermKind::FreeConst { .. } => {
34                self.normalize_free_alias(goal).map_err(Into::into)
35            }
36            ty::AliasTermKind::AnonConst { .. } => {
37                self.normalize_anon_const(goal).map_err(Into::into)
38            }
39        }
40    }
41
42    fn normalize_associated_term(
43        &mut self,
44        goal: Goal<I, ProjectionPredicate<I>>,
45    ) -> QueryResultOrRerunNonErased<I> {
46        let ty::ProjectionPredicate { projection_term: alias, term } = goal.predicate;
47        let unconstrained_term = self.next_term_infer_of_kind(term);
48        let normalizes_to =
49            goal.with(self.cx(), ty::NormalizesTo { alias, term: unconstrained_term });
50
51        // We don't want candidate selection when normalizing associated terms to be impacted by
52        // the expected term. Normalization should behave like a function of just the alias being
53        // normalized. Because of this, we use an internal `NormalizesTo` goal for which the
54        // expected term is always fully unconstrained and then equate that to the actual expected
55        // term afterwards.
56        //
57        // But this results in weaker type inference if there's a nested where-clause when
58        // normalizing which we can actually make progress on based on the expected term. To avoid
59        // this, we return ambiguous nested goals for `NormalizesTo` to this context and register
60        // them as if they were this `Projection` goal's own nested goals. (See #122687)
61        //
62        // After registering those goals, we equate the original expected term to the normalization
63        // result. Although equating them can add inference constraint to the alias term, we don't
64        // reevaluate this special `NormalizesTo` goal. But that's fine because as those inference
65        // constraints should cause the caller to reevaluate the current `Projection `goal, which
66        // will then also reevaluate the `NormalizesTo` goal.
67        let (
68            NestedNormalizationGoals(nested_goals),
69            GoalEvaluation { goal: _, certainty, stalled_on: _, has_changed: _ },
70        ) = self.evaluate_goal_raw(GoalSource::TypeRelating, normalizes_to, None)?;
71
72        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs:72",
                        "rustc_next_trait_solver::solve::project_goals",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(72u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_next_trait_solver::solve::project_goals"),
                        ::tracing_core::field::FieldSet::new(&["nested_goals"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&nested_goals)
                                            as &dyn Value))])
            });
    } else { ; }
};trace!(?nested_goals);
73
74        // Add a `make_canonical_response` probe step so that we treat this as
75        // a candidate, even if `try_evaluate_added_goals` bails due to an error.
76        // It's `Certainty::AMBIGUOUS` because this candidate is not "finished",
77        // since equating the normalized terms will lead to additional constraints.
78        self.inspect.make_canonical_response(Certainty::AMBIGUOUS);
79
80        // FIXME: We shouldn't be doing this in the long term in favor of eager
81        // normalization.
82        // Normalize alias types in rhs. This is done in `EvalCtxt::add_goal` for nested
83        // goals, but we might be evaluating the root goal.
84        let term = self.replace_alias_with_infer(term, GoalSource::TypeRelating, goal.param_env);
85
86        // Apply the constraints.
87        self.try_evaluate_added_goals()?;
88
89        // Finally, equate the goal's RHS with the unconstrained var.
90        //
91        // SUBTLE:
92        // We structurally relate aliases here. This is necessary
93        // as we otherwise emit a nested `AliasRelate` goal in case the
94        // returned term is a rigid alias, resulting in overflow.
95        //
96        // It is correct as both `goal.predicate.term` and `unconstrained_rhs`
97        // start out as an unconstrained inference variable so any aliases get
98        // fully normalized when instantiating it.
99        //
100        // FIXME: Strictly speaking this may be incomplete if the normalized-to
101        // type contains an ambiguous alias referencing bound regions. We should
102        // consider changing this to only use "shallow structural equality".
103        self.eq_structurally_relating_aliases(goal.param_env, term, unconstrained_term)?;
104
105        // Add the nested goals from normalization to our own nested goals.
106        for (s, g) in nested_goals {
107            self.add_goal(s, g);
108        }
109
110        self.evaluate_added_goals_and_make_canonical_response(certainty)
111    }
112}