| //! Implements the `AliasRelate` goal, which is used when unifying aliases. |
| //! Doing this via a separate goal is called "deferred alias relation" and part |
| //! of our more general approach to "lazy normalization". |
| //! |
| //! This is done by first structurally normalizing both sides of the goal, ending |
| //! up in either a concrete type, rigid alias, or an infer variable. |
| //! These are related further according to the rules below: |
| //! |
| //! (1.) If we end up with two rigid aliases, then we relate them structurally. |
| //! |
| //! (2.) If we end up with an infer var and a rigid alias, then we instantiate |
| //! the infer var with the constructor of the alias and then recursively relate |
| //! the terms. |
| //! |
| //! (3.) Otherwise, if we end with two rigid (non-projection) or infer types, |
| //! relate them structurally. |
| |
| use rustc_type_ir::inherent::*; |
| use rustc_type_ir::solve::GoalSource; |
| use rustc_type_ir::{self as ty, Interner}; |
| use tracing::{instrument, trace}; |
| |
| use crate::delegate::SolverDelegate; |
| use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; |
| |
| impl<D, I> EvalCtxt<'_, D> |
| where |
| D: SolverDelegate<Interner = I>, |
| I: Interner, |
| { |
| #[instrument(level = "trace", skip(self), ret)] |
| pub(super) fn compute_alias_relate_goal( |
| &mut self, |
| goal: Goal<I, (I::Term, I::Term, ty::AliasRelationDirection)>, |
| ) -> QueryResult<I> { |
| let cx = self.cx(); |
| let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; |
| |
| // Check that the alias-relate goal is reasonable. Writeback for |
| // `coroutine_stalled_predicates` can replace alias terms with |
| // `{type error}` if the alias still contains infer vars, so we also |
| // accept alias-relate goals where one of the terms is an error. |
| debug_assert!( |
| lhs.to_alias_term().is_some() |
| || rhs.to_alias_term().is_some() |
| || lhs.is_error() |
| || rhs.is_error() |
| ); |
| |
| // Structurally normalize the lhs. |
| let lhs = if let Some(alias) = lhs.to_alias_term() { |
| let term = self.next_term_infer_of_kind(lhs); |
| self.add_goal( |
| GoalSource::TypeRelating, |
| goal.with(cx, ty::NormalizesTo { alias, term }), |
| ); |
| term |
| } else { |
| lhs |
| }; |
| |
| // Structurally normalize the rhs. |
| let rhs = if let Some(alias) = rhs.to_alias_term() { |
| let term = self.next_term_infer_of_kind(rhs); |
| self.add_goal( |
| GoalSource::TypeRelating, |
| goal.with(cx, ty::NormalizesTo { alias, term }), |
| ); |
| term |
| } else { |
| rhs |
| }; |
| |
| // Add a `make_canonical_response` probe step so that we treat this as |
| // a candidate, even if `try_evaluate_added_goals` bails due to an error. |
| // It's `Certainty::AMBIGUOUS` because this candidate is not "finished", |
| // since equating the normalized terms will lead to additional constraints. |
| self.inspect.make_canonical_response(Certainty::AMBIGUOUS); |
| |
| // Apply the constraints. |
| self.try_evaluate_added_goals()?; |
| let lhs = self.resolve_vars_if_possible(lhs); |
| let rhs = self.resolve_vars_if_possible(rhs); |
| trace!(?lhs, ?rhs); |
| |
| let variance = match direction { |
| ty::AliasRelationDirection::Equate => ty::Invariant, |
| ty::AliasRelationDirection::Subtype => ty::Covariant, |
| }; |
| match (lhs.to_alias_term(), rhs.to_alias_term()) { |
| (None, None) => { |
| self.relate(param_env, lhs, variance, rhs)?; |
| self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| } |
| |
| (Some(alias), None) => { |
| self.relate_rigid_alias_non_alias(param_env, alias, variance, rhs)?; |
| self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| } |
| (None, Some(alias)) => { |
| self.relate_rigid_alias_non_alias( |
| param_env, |
| alias, |
| variance.xform(ty::Contravariant), |
| lhs, |
| )?; |
| self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| } |
| |
| (Some(alias_lhs), Some(alias_rhs)) => { |
| self.relate(param_env, alias_lhs, variance, alias_rhs)?; |
| self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) |
| } |
| } |
| } |
| } |