alias_relate.rs - source (original) (raw)

rustc_next_trait_solver/solve/

alias_relate.rs

1//! Implements the `AliasRelate` goal, which is used when unifying aliases.
2//! Doing this via a separate goal is called "deferred alias relation" and part
3//! of our more general approach to "lazy normalization".
4//!
5//! This is done by first structurally normalizing both sides of the goal, ending
6//! up in either a concrete type, rigid alias, or an infer variable.
7//! These are related further according to the rules below:
8//!
9//! (1.) If we end up with two rigid aliases, then we relate them structurally.
10//!
11//! (2.) If we end up with an infer var and a rigid alias, then we instantiate
12//! the infer var with the constructor of the alias and then recursively relate
13//! the terms.
14//!
15//! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
16//! relate them structurally.
17
18use rustc_type_ir::inherent::*;
19use rustc_type_ir::solve::GoalSource;
20use rustc_type_ir::{self as ty, Interner};
21use tracing::{instrument, trace};
22
23use crate::delegate::SolverDelegate;
24use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult};
25
26impl<D, I> EvalCtxt<'_, D>
27where
28    D: SolverDelegate<Interner = I>,
29    I: Interner,
30{
31    #[instrument(level = "trace", skip(self), ret)]
32    pub(super) fn compute_alias_relate_goal(
33        &mut self,
34        goal: Goal<I, (I::Term, I::Term, ty::AliasRelationDirection)>,
35    ) -> QueryResult<I> {
36        let cx = self.cx();
37        let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
38
39        // Check that the alias-relate goal is reasonable. Writeback for
40        // `coroutine_stalled_predicates` can replace alias terms with
41        // `{type error}` if the alias still contains infer vars, so we also
42        // accept alias-relate goals where one of the terms is an error.
43        debug_assert!(
44            lhs.to_alias_term().is_some()
45                || rhs.to_alias_term().is_some()
46                || lhs.is_error()
47                || rhs.is_error()
48        );
49
50        // Structurally normalize the lhs.
51        let lhs = if let Some(alias) = lhs.to_alias_term() {
52            let term = self.next_term_infer_of_kind(lhs);
53            self.add_goal(
54                GoalSource::TypeRelating,
55                goal.with(cx, ty::NormalizesTo { alias, term }),
56            );
57            term
58        } else {
59            lhs
60        };
61
62        // Structurally normalize the rhs.
63        let rhs = if let Some(alias) = rhs.to_alias_term() {
64            let term = self.next_term_infer_of_kind(rhs);
65            self.add_goal(
66                GoalSource::TypeRelating,
67                goal.with(cx, ty::NormalizesTo { alias, term }),
68            );
69            term
70        } else {
71            rhs
72        };
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        // Apply the constraints.
81        self.try_evaluate_added_goals()?;
82        let lhs = self.resolve_vars_if_possible(lhs);
83        let rhs = self.resolve_vars_if_possible(rhs);
84        trace!(?lhs, ?rhs);
85
86        let variance = match direction {
87            ty::AliasRelationDirection::Equate => ty::Invariant,
88            ty::AliasRelationDirection::Subtype => ty::Covariant,
89        };
90        match (lhs.to_alias_term(), rhs.to_alias_term()) {
91            (None, None) => {
92                self.relate(param_env, lhs, variance, rhs)?;
93                self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
94            }
95
96            (Some(alias), None) => {
97                self.relate_rigid_alias_non_alias(param_env, alias, variance, rhs)?;
98                self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
99            }
100            (None, Some(alias)) => {
101                self.relate_rigid_alias_non_alias(
102                    param_env,
103                    alias,
104                    variance.xform(ty::Contravariant),
105                    lhs,
106                )?;
107                self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
108            }
109
110            (Some(alias_lhs), Some(alias_rhs)) => {
111                self.relate(param_env, alias_lhs, variance, alias_rhs)?;
112                self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
113            }
114        }
115    }
116}