2023-07-24 08:37:40 -07:00
|
|
|
//! 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".
|
2023-07-23 12:30:52 -07:00
|
|
|
//!
|
|
|
|
|
//! This goal, e.g. `A alias-relate B`, may be satisfied by one of three branches:
|
|
|
|
|
//! * normalizes-to: If `A` is a projection, we can prove the equivalent
|
|
|
|
|
//! projection predicate with B as the right-hand side of the projection.
|
|
|
|
|
//! This goal is computed in both directions, if both are aliases.
|
|
|
|
|
//! * subst-relate: Equate `A` and `B` by their substs, if they're both
|
|
|
|
|
//! aliases with the same def-id.
|
|
|
|
|
//! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both
|
|
|
|
|
//! may apply, then we can compute the "intersection" of both normalizes-to by
|
|
|
|
|
//! performing them together. This is used specifically to resolve ambiguities.
|
2023-11-09 11:06:48 +01:00
|
|
|
use super::EvalCtxt;
|
|
|
|
|
use rustc_infer::infer::DefineOpaqueTypes;
|
2023-05-27 19:05:09 +00:00
|
|
|
use rustc_infer::traits::query::NoSolution;
|
|
|
|
|
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
|
|
|
|
use rustc_middle::ty;
|
|
|
|
|
|
|
|
|
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|
|
|
|
#[instrument(level = "debug", skip(self), ret)]
|
|
|
|
|
pub(super) fn compute_alias_relate_goal(
|
|
|
|
|
&mut self,
|
|
|
|
|
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
|
|
|
|
|
) -> QueryResult<'tcx> {
|
|
|
|
|
let tcx = self.tcx();
|
|
|
|
|
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
|
|
|
|
|
|
2023-11-09 11:06:48 +01:00
|
|
|
let Some(lhs) = self.try_normalize_term(param_env, lhs)? else {
|
|
|
|
|
return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
|
|
|
|
|
};
|
2023-05-27 19:05:09 +00:00
|
|
|
|
2023-11-09 11:06:48 +01:00
|
|
|
let Some(rhs) = self.try_normalize_term(param_env, rhs)? else {
|
|
|
|
|
return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
|
|
|
|
|
};
|
2023-05-27 19:05:09 +00:00
|
|
|
|
2023-11-09 11:06:48 +01:00
|
|
|
let variance = match direction {
|
|
|
|
|
ty::AliasRelationDirection::Equate => ty::Variance::Invariant,
|
|
|
|
|
ty::AliasRelationDirection::Subtype => ty::Variance::Covariant,
|
|
|
|
|
};
|
2023-05-27 19:05:09 +00:00
|
|
|
|
2023-11-09 11:06:48 +01:00
|
|
|
match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
|
|
|
|
|
(None, None) => {
|
|
|
|
|
self.relate(param_env, lhs, variance, rhs)?;
|
|
|
|
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
|
|
|
|
}
|
2023-05-27 19:05:09 +00:00
|
|
|
|
2023-11-09 11:06:48 +01:00
|
|
|
(Some(alias), None) => {
|
|
|
|
|
if rhs.is_infer() {
|
|
|
|
|
self.relate(param_env, lhs, variance, rhs)?;
|
|
|
|
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
|
|
|
|
} else if alias.is_opaque(tcx) {
|
|
|
|
|
self.define_opaque(param_env, alias, rhs)
|
2023-05-27 19:05:09 +00:00
|
|
|
} else {
|
2023-11-09 11:06:48 +01:00
|
|
|
Err(NoSolution)
|
2023-05-27 19:05:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-11-09 11:06:48 +01:00
|
|
|
(None, Some(alias)) => {
|
|
|
|
|
if lhs.is_infer() {
|
|
|
|
|
self.relate(param_env, lhs, variance, rhs)?;
|
|
|
|
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
|
|
|
|
} else if alias.is_opaque(tcx) {
|
|
|
|
|
self.define_opaque(param_env, alias, lhs)
|
|
|
|
|
} else {
|
|
|
|
|
Err(NoSolution)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(Some(alias_lhs), Some(alias_rhs)) => {
|
|
|
|
|
self.relate_rigid_alias_or_opaque(param_env, alias_lhs, variance, alias_rhs)
|
|
|
|
|
}
|
2023-05-27 19:05:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-09 11:06:48 +01:00
|
|
|
/// Normalize the `term` to equate it later. This does not define opaque types.
|
|
|
|
|
#[instrument(level = "debug", skip(self, param_env), ret)]
|
|
|
|
|
fn try_normalize_term(
|
2023-05-27 19:05:09 +00:00
|
|
|
&mut self,
|
|
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2023-11-09 11:06:48 +01:00
|
|
|
term: ty::Term<'tcx>,
|
|
|
|
|
) -> Result<Option<ty::Term<'tcx>>, NoSolution> {
|
|
|
|
|
match term.unpack() {
|
|
|
|
|
ty::TermKind::Ty(ty) => {
|
|
|
|
|
// We do no define opaque types here but instead do so in `relate_rigid_alias_or_opaque`.
|
|
|
|
|
Ok(self
|
|
|
|
|
.try_normalize_ty_recur(param_env, DefineOpaqueTypes::No, 0, ty)
|
|
|
|
|
.map(Into::into))
|
|
|
|
|
}
|
|
|
|
|
ty::TermKind::Const(_) => {
|
|
|
|
|
if let Some(alias) = term.to_alias_ty(self.tcx()) {
|
|
|
|
|
let term = self.next_term_infer_of_kind(term);
|
|
|
|
|
self.add_goal(Goal::new(
|
|
|
|
|
self.tcx(),
|
|
|
|
|
param_env,
|
2023-12-07 18:20:27 +01:00
|
|
|
ty::NormalizesTo { alias, term },
|
2023-11-09 11:06:48 +01:00
|
|
|
));
|
|
|
|
|
self.try_evaluate_added_goals()?;
|
|
|
|
|
Ok(Some(self.resolve_vars_if_possible(term)))
|
|
|
|
|
} else {
|
|
|
|
|
Ok(Some(term))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-05-27 19:05:09 +00:00
|
|
|
}
|
|
|
|
|
|
2023-11-09 11:06:48 +01:00
|
|
|
fn define_opaque(
|
2023-05-27 19:27:59 +00:00
|
|
|
&mut self,
|
|
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2023-11-09 11:06:48 +01:00
|
|
|
opaque: ty::AliasTy<'tcx>,
|
|
|
|
|
term: ty::Term<'tcx>,
|
|
|
|
|
) -> QueryResult<'tcx> {
|
2023-12-07 18:20:27 +01:00
|
|
|
self.add_goal(Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }));
|
2023-11-09 11:06:48 +01:00
|
|
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
2023-05-27 19:27:59 +00:00
|
|
|
}
|
|
|
|
|
|
2023-11-09 11:06:48 +01:00
|
|
|
fn relate_rigid_alias_or_opaque(
|
2023-05-27 19:05:09 +00:00
|
|
|
&mut self,
|
|
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2023-11-09 11:06:48 +01:00
|
|
|
lhs: ty::AliasTy<'tcx>,
|
|
|
|
|
variance: ty::Variance,
|
|
|
|
|
rhs: ty::AliasTy<'tcx>,
|
2023-05-27 19:05:09 +00:00
|
|
|
) -> QueryResult<'tcx> {
|
2023-11-09 11:06:48 +01:00
|
|
|
let tcx = self.tcx();
|
|
|
|
|
let mut candidates = vec![];
|
|
|
|
|
if lhs.is_opaque(tcx) {
|
|
|
|
|
candidates.extend(
|
|
|
|
|
self.probe_misc_candidate("define-lhs-opaque")
|
|
|
|
|
.enter(|ecx| ecx.define_opaque(param_env, lhs, rhs.to_ty(tcx).into())),
|
|
|
|
|
);
|
|
|
|
|
}
|
2023-05-27 19:05:09 +00:00
|
|
|
|
2023-11-09 11:06:48 +01:00
|
|
|
if rhs.is_opaque(tcx) {
|
|
|
|
|
candidates.extend(
|
|
|
|
|
self.probe_misc_candidate("define-rhs-opaque")
|
|
|
|
|
.enter(|ecx| ecx.define_opaque(param_env, rhs, lhs.to_ty(tcx).into())),
|
|
|
|
|
);
|
|
|
|
|
}
|
2023-05-27 19:27:59 +00:00
|
|
|
|
2023-11-09 11:06:48 +01:00
|
|
|
candidates.extend(self.probe_misc_candidate("args-relate").enter(|ecx| {
|
|
|
|
|
ecx.relate(param_env, lhs, variance, rhs)?;
|
2023-07-04 16:59:21 +02:00
|
|
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
2023-11-09 11:06:48 +01:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
if let Some(result) = self.try_merge_responses(&candidates) {
|
|
|
|
|
Ok(result)
|
|
|
|
|
} else {
|
|
|
|
|
self.flounder(&candidates)
|
|
|
|
|
}
|
2023-05-27 19:27:59 +00:00
|
|
|
}
|
2023-05-27 19:05:09 +00:00
|
|
|
}
|