mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-28 17:53:56 +00:00
Uplift super_combine
This commit is contained in:
parent
09da2ebd63
commit
ce7a61b9d0
@ -11,6 +11,7 @@ use rustc_middle::span_bug;
|
|||||||
use rustc_middle::traits::ObligationCause;
|
use rustc_middle::traits::ObligationCause;
|
||||||
use rustc_middle::traits::query::NoSolution;
|
use rustc_middle::traits::query::NoSolution;
|
||||||
use rustc_middle::ty::fold::FnMutDelegate;
|
use rustc_middle::ty::fold::FnMutDelegate;
|
||||||
|
use rustc_middle::ty::relate::combine::InferCtxtCombineExt;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
|
@ -1,22 +1,27 @@
|
|||||||
///! Definition of `InferCtxtLike` from the librarified type layer.
|
///! Definition of `InferCtxtLike` from the librarified type layer.
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
|
use rustc_middle::infer::unify_key::EffectVarValue;
|
||||||
use rustc_middle::traits::ObligationCause;
|
use rustc_middle::traits::ObligationCause;
|
||||||
use rustc_middle::traits::solve::{Goal, NoSolution, SolverMode};
|
use rustc_middle::traits::solve::{Goal, NoSolution, SolverMode};
|
||||||
use rustc_middle::ty::fold::TypeFoldable;
|
use rustc_middle::ty::fold::TypeFoldable;
|
||||||
|
use rustc_middle::ty::relate::combine::PredicateEmittingRelation;
|
||||||
|
use rustc_middle::ty::relate::{Relate, RelateResult};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::{DUMMY_SP, ErrorGuaranteed};
|
||||||
use rustc_type_ir::InferCtxtLike;
|
|
||||||
use rustc_type_ir::relate::Relate;
|
|
||||||
|
|
||||||
use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin};
|
use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin};
|
||||||
|
|
||||||
impl<'tcx> InferCtxtLike for InferCtxt<'tcx> {
|
impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
||||||
type Interner = TyCtxt<'tcx>;
|
type Interner = TyCtxt<'tcx>;
|
||||||
|
|
||||||
fn cx(&self) -> TyCtxt<'tcx> {
|
fn cx(&self) -> TyCtxt<'tcx> {
|
||||||
self.tcx
|
self.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_trait_solver(&self) -> bool {
|
||||||
|
self.next_trait_solver
|
||||||
|
}
|
||||||
|
|
||||||
fn solver_mode(&self) -> ty::solve::SolverMode {
|
fn solver_mode(&self) -> ty::solve::SolverMode {
|
||||||
match self.intercrate {
|
match self.intercrate {
|
||||||
true => SolverMode::Coherence,
|
true => SolverMode::Coherence,
|
||||||
@ -131,6 +136,59 @@ impl<'tcx> InferCtxtLike for InferCtxt<'tcx> {
|
|||||||
self.enter_forall(value, f)
|
self.enter_forall(value, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn equate_int_vids_raw(&self, a: rustc_type_ir::IntVid, b: rustc_type_ir::IntVid) {
|
||||||
|
self.inner.borrow_mut().int_unification_table().union(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equate_float_vids_raw(&self, a: rustc_type_ir::FloatVid, b: rustc_type_ir::FloatVid) {
|
||||||
|
self.inner.borrow_mut().float_unification_table().union(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equate_const_vids_raw(&self, a: rustc_type_ir::ConstVid, b: rustc_type_ir::ConstVid) {
|
||||||
|
self.inner.borrow_mut().const_unification_table().union(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equate_effect_vids_raw(&self, a: rustc_type_ir::EffectVid, b: rustc_type_ir::EffectVid) {
|
||||||
|
self.inner.borrow_mut().effect_unification_table().union(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instantiate_int_var_raw(
|
||||||
|
&self,
|
||||||
|
vid: rustc_type_ir::IntVid,
|
||||||
|
value: rustc_type_ir::IntVarValue,
|
||||||
|
) {
|
||||||
|
self.inner.borrow_mut().int_unification_table().union_value(vid, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instantiate_float_var_raw(
|
||||||
|
&self,
|
||||||
|
vid: rustc_type_ir::FloatVid,
|
||||||
|
value: rustc_type_ir::FloatVarValue,
|
||||||
|
) {
|
||||||
|
self.inner.borrow_mut().float_unification_table().union_value(vid, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instantiate_effect_var_raw(&self, vid: rustc_type_ir::EffectVid, value: ty::Const<'tcx>) {
|
||||||
|
self.inner
|
||||||
|
.borrow_mut()
|
||||||
|
.effect_unification_table()
|
||||||
|
.union_value(vid, EffectVarValue::Known(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>(
|
||||||
|
&self,
|
||||||
|
relation: &mut R,
|
||||||
|
target_is_expected: bool,
|
||||||
|
target_vid: rustc_type_ir::ConstVid,
|
||||||
|
source_ct: ty::Const<'tcx>,
|
||||||
|
) -> RelateResult<'tcx, ()> {
|
||||||
|
self.instantiate_const_var(relation, target_is_expected, target_vid, source_ct)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
|
||||||
|
self.set_tainted_by_errors(e)
|
||||||
|
}
|
||||||
|
|
||||||
fn relate<T: Relate<TyCtxt<'tcx>>>(
|
fn relate<T: Relate<TyCtxt<'tcx>>>(
|
||||||
&self,
|
&self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
@ -154,6 +212,9 @@ impl<'tcx> InferCtxtLike for InferCtxt<'tcx> {
|
|||||||
fn shallow_resolve(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
fn shallow_resolve(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
self.shallow_resolve(ty)
|
self.shallow_resolve(ty)
|
||||||
}
|
}
|
||||||
|
fn shallow_resolve_const(&self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||||
|
self.shallow_resolve_const(ct)
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||||
where
|
where
|
||||||
|
@ -1,245 +0,0 @@
|
|||||||
//! There are four type combiners: `TypeRelating`, `Lub`, and `Glb`,
|
|
||||||
//! and `NllTypeRelating` in rustc_borrowck, which is only used for NLL.
|
|
||||||
//!
|
|
||||||
//! Each implements the trait [TypeRelation] and contains methods for
|
|
||||||
//! combining two instances of various things and yielding a new instance.
|
|
||||||
//! These combiner methods always yield a `Result<T>`. To relate two
|
|
||||||
//! types, you can use `infcx.at(cause, param_env)` which then allows
|
|
||||||
//! you to use the relevant methods of [At](crate::infer::at::At).
|
|
||||||
//!
|
|
||||||
//! Combiners mostly do their specific behavior and then hand off the
|
|
||||||
//! bulk of the work to [InferCtxt::super_combine_tys] and
|
|
||||||
//! [InferCtxt::super_combine_consts].
|
|
||||||
//!
|
|
||||||
//! Combining two types may have side-effects on the inference contexts
|
|
||||||
//! which can be undone by using snapshots. You probably want to use
|
|
||||||
//! either [InferCtxt::commit_if_ok] or [InferCtxt::probe].
|
|
||||||
//!
|
|
||||||
//! On success, the LUB/GLB operations return the appropriate bound. The
|
|
||||||
//! return value of `Equate` or `Sub` shouldn't really be used.
|
|
||||||
|
|
||||||
use rustc_middle::bug;
|
|
||||||
use rustc_middle::infer::unify_key::EffectVarValue;
|
|
||||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
|
||||||
use rustc_middle::ty::{self, InferConst, IntType, Ty, TypeVisitableExt, UintType};
|
|
||||||
pub use rustc_next_trait_solver::relate::combine::*;
|
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
use super::{RelateResult, StructurallyRelateAliases};
|
|
||||||
use crate::infer::{InferCtxt, relate};
|
|
||||||
|
|
||||||
impl<'tcx> InferCtxt<'tcx> {
|
|
||||||
pub fn super_combine_tys<R>(
|
|
||||||
&self,
|
|
||||||
relation: &mut R,
|
|
||||||
a: Ty<'tcx>,
|
|
||||||
b: Ty<'tcx>,
|
|
||||||
) -> RelateResult<'tcx, Ty<'tcx>>
|
|
||||||
where
|
|
||||||
R: PredicateEmittingRelation<InferCtxt<'tcx>>,
|
|
||||||
{
|
|
||||||
debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
|
|
||||||
debug_assert!(!a.has_escaping_bound_vars());
|
|
||||||
debug_assert!(!b.has_escaping_bound_vars());
|
|
||||||
|
|
||||||
match (a.kind(), b.kind()) {
|
|
||||||
(&ty::Error(e), _) | (_, &ty::Error(e)) => {
|
|
||||||
self.set_tainted_by_errors(e);
|
|
||||||
return Ok(Ty::new_error(self.tcx, e));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Relate integral variables to other types
|
|
||||||
(&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => {
|
|
||||||
self.inner.borrow_mut().int_unification_table().union(a_id, b_id);
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
(&ty::Infer(ty::IntVar(v_id)), &ty::Int(v)) => {
|
|
||||||
self.unify_integral_variable(v_id, IntType(v));
|
|
||||||
Ok(b)
|
|
||||||
}
|
|
||||||
(&ty::Int(v), &ty::Infer(ty::IntVar(v_id))) => {
|
|
||||||
self.unify_integral_variable(v_id, IntType(v));
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
(&ty::Infer(ty::IntVar(v_id)), &ty::Uint(v)) => {
|
|
||||||
self.unify_integral_variable(v_id, UintType(v));
|
|
||||||
Ok(b)
|
|
||||||
}
|
|
||||||
(&ty::Uint(v), &ty::Infer(ty::IntVar(v_id))) => {
|
|
||||||
self.unify_integral_variable(v_id, UintType(v));
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Relate floating-point variables to other types
|
|
||||||
(&ty::Infer(ty::FloatVar(a_id)), &ty::Infer(ty::FloatVar(b_id))) => {
|
|
||||||
self.inner.borrow_mut().float_unification_table().union(a_id, b_id);
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
(&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => {
|
|
||||||
self.unify_float_variable(v_id, ty::FloatVarValue::Known(v));
|
|
||||||
Ok(b)
|
|
||||||
}
|
|
||||||
(&ty::Float(v), &ty::Infer(ty::FloatVar(v_id))) => {
|
|
||||||
self.unify_float_variable(v_id, ty::FloatVarValue::Known(v));
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
|
|
||||||
(ty::Alias(..), ty::Infer(ty::TyVar(_))) | (ty::Infer(ty::TyVar(_)), ty::Alias(..))
|
|
||||||
if self.next_trait_solver() =>
|
|
||||||
{
|
|
||||||
bug!(
|
|
||||||
"We do not expect to encounter `TyVar` this late in combine \
|
|
||||||
-- they should have been handled earlier"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
(_, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)))
|
|
||||||
| (ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), _)
|
|
||||||
if self.next_trait_solver() =>
|
|
||||||
{
|
|
||||||
bug!("We do not expect to encounter `Fresh` variables in the new solver")
|
|
||||||
}
|
|
||||||
|
|
||||||
(_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => {
|
|
||||||
match relation.structurally_relate_aliases() {
|
|
||||||
StructurallyRelateAliases::Yes => {
|
|
||||||
relate::structurally_relate_tys(relation, a, b)
|
|
||||||
}
|
|
||||||
StructurallyRelateAliases::No => {
|
|
||||||
relation.register_alias_relate_predicate(a, b);
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All other cases of inference are errors
|
|
||||||
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
|
|
||||||
Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// During coherence, opaque types should be treated as *possibly*
|
|
||||||
// equal to any other type (except for possibly itself). This is an
|
|
||||||
// extremely heavy hammer, but can be relaxed in a forwards-compatible
|
|
||||||
// way later.
|
|
||||||
(&ty::Alias(ty::Opaque, _), _) | (_, &ty::Alias(ty::Opaque, _)) if self.intercrate => {
|
|
||||||
relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => relate::structurally_relate_tys(relation, a, b),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn super_combine_consts<R>(
|
|
||||||
&self,
|
|
||||||
relation: &mut R,
|
|
||||||
a: ty::Const<'tcx>,
|
|
||||||
b: ty::Const<'tcx>,
|
|
||||||
) -> RelateResult<'tcx, ty::Const<'tcx>>
|
|
||||||
where
|
|
||||||
R: PredicateEmittingRelation<InferCtxt<'tcx>>,
|
|
||||||
{
|
|
||||||
debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
|
|
||||||
debug_assert!(!a.has_escaping_bound_vars());
|
|
||||||
debug_assert!(!b.has_escaping_bound_vars());
|
|
||||||
|
|
||||||
if a == b {
|
|
||||||
return Ok(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
let a = self.shallow_resolve_const(a);
|
|
||||||
let b = self.shallow_resolve_const(b);
|
|
||||||
|
|
||||||
match (a.kind(), b.kind()) {
|
|
||||||
(
|
|
||||||
ty::ConstKind::Infer(InferConst::Var(a_vid)),
|
|
||||||
ty::ConstKind::Infer(InferConst::Var(b_vid)),
|
|
||||||
) => {
|
|
||||||
self.inner.borrow_mut().const_unification_table().union(a_vid, b_vid);
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
(
|
|
||||||
ty::ConstKind::Infer(InferConst::EffectVar(a_vid)),
|
|
||||||
ty::ConstKind::Infer(InferConst::EffectVar(b_vid)),
|
|
||||||
) => {
|
|
||||||
self.inner.borrow_mut().effect_unification_table().union(a_vid, b_vid);
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
// All other cases of inference with other variables are errors.
|
|
||||||
(
|
|
||||||
ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
|
|
||||||
ty::ConstKind::Infer(_),
|
|
||||||
)
|
|
||||||
| (
|
|
||||||
ty::ConstKind::Infer(_),
|
|
||||||
ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
|
|
||||||
) => {
|
|
||||||
bug!(
|
|
||||||
"tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
(ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
|
|
||||||
self.instantiate_const_var(relation, true, vid, b)?;
|
|
||||||
Ok(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
|
|
||||||
self.instantiate_const_var(relation, false, vid, a)?;
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
(ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => {
|
|
||||||
Ok(self.unify_effect_variable(vid, b))
|
|
||||||
}
|
|
||||||
|
|
||||||
(_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => {
|
|
||||||
Ok(self.unify_effect_variable(vid, a))
|
|
||||||
}
|
|
||||||
|
|
||||||
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
|
|
||||||
if self.tcx.features().generic_const_exprs || self.next_trait_solver() =>
|
|
||||||
{
|
|
||||||
match relation.structurally_relate_aliases() {
|
|
||||||
StructurallyRelateAliases::No => {
|
|
||||||
relation.register_predicates([if self.next_trait_solver() {
|
|
||||||
ty::PredicateKind::AliasRelate(
|
|
||||||
a.into(),
|
|
||||||
b.into(),
|
|
||||||
ty::AliasRelationDirection::Equate,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
ty::PredicateKind::ConstEquate(a, b)
|
|
||||||
}]);
|
|
||||||
|
|
||||||
Ok(b)
|
|
||||||
}
|
|
||||||
StructurallyRelateAliases::Yes => {
|
|
||||||
relate::structurally_relate_consts(relation, a, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => relate::structurally_relate_consts(relation, a, b),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn unify_integral_variable(&self, vid: ty::IntVid, val: ty::IntVarValue) {
|
|
||||||
self.inner.borrow_mut().int_unification_table().union_value(vid, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn unify_float_variable(&self, vid: ty::FloatVid, val: ty::FloatVarValue) {
|
|
||||||
self.inner.borrow_mut().float_unification_table().union_value(vid, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unify_effect_variable(&self, vid: ty::EffectVid, val: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
|
||||||
self.inner
|
|
||||||
.borrow_mut()
|
|
||||||
.effect_unification_table()
|
|
||||||
.union_value(vid, EffectVarValue::Known(val));
|
|
||||||
val
|
|
||||||
}
|
|
||||||
}
|
|
@ -183,7 +183,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
///
|
///
|
||||||
/// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
|
/// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
|
||||||
#[instrument(level = "debug", skip(self, relation))]
|
#[instrument(level = "debug", skip(self, relation))]
|
||||||
pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
|
pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
|
||||||
&self,
|
&self,
|
||||||
relation: &mut R,
|
relation: &mut R,
|
||||||
target_is_expected: bool,
|
target_is_expected: bool,
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
|
//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
|
||||||
|
|
||||||
use rustc_middle::traits::solve::Goal;
|
use rustc_middle::traits::solve::Goal;
|
||||||
|
use rustc_middle::ty::relate::combine::InferCtxtCombineExt;
|
||||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -3,12 +3,10 @@
|
|||||||
//! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc).
|
//! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc).
|
||||||
|
|
||||||
pub use rustc_middle::ty::relate::RelateResult;
|
pub use rustc_middle::ty::relate::RelateResult;
|
||||||
pub use rustc_next_trait_solver::relate::*;
|
pub use rustc_type_ir::relate::combine::PredicateEmittingRelation;
|
||||||
|
pub use rustc_type_ir::relate::*;
|
||||||
pub use self::combine::PredicateEmittingRelation;
|
|
||||||
|
|
||||||
#[allow(hidden_glob_reexports)]
|
#[allow(hidden_glob_reexports)]
|
||||||
pub(super) mod combine;
|
|
||||||
mod generalize;
|
mod generalize;
|
||||||
mod higher_ranked;
|
mod higher_ranked;
|
||||||
pub(super) mod lattice;
|
pub(super) mod lattice;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use rustc_middle::traits::solve::Goal;
|
use rustc_middle::traits::solve::Goal;
|
||||||
|
use rustc_middle::ty::relate::combine::InferCtxtCombineExt;
|
||||||
use rustc_middle::ty::relate::{
|
use rustc_middle::ty::relate::{
|
||||||
Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances,
|
Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances,
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,5 @@
|
|||||||
pub mod canonicalizer;
|
pub mod canonicalizer;
|
||||||
pub mod coherence;
|
pub mod coherence;
|
||||||
pub mod delegate;
|
pub mod delegate;
|
||||||
pub mod relate;
|
|
||||||
pub mod resolve;
|
pub mod resolve;
|
||||||
pub mod solve;
|
pub mod solve;
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
pub use rustc_type_ir::relate::*;
|
|
||||||
|
|
||||||
pub mod combine;
|
|
||||||
|
|
||||||
/// Whether aliases should be related structurally or not. Used
|
|
||||||
/// to adjust the behavior of generalization and combine.
|
|
||||||
///
|
|
||||||
/// This should always be `No` unless in a few special-cases when
|
|
||||||
/// instantiating canonical responses and in the new solver. Each
|
|
||||||
/// such case should have a comment explaining why it is used.
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub enum StructurallyRelateAliases {
|
|
||||||
Yes,
|
|
||||||
No,
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
pub use rustc_type_ir::relate::*;
|
|
||||||
use rustc_type_ir::solve::Goal;
|
|
||||||
use rustc_type_ir::{InferCtxtLike, Interner, Upcast};
|
|
||||||
|
|
||||||
use super::StructurallyRelateAliases;
|
|
||||||
|
|
||||||
pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>:
|
|
||||||
TypeRelation<I>
|
|
||||||
where
|
|
||||||
Infcx: InferCtxtLike<Interner = I>,
|
|
||||||
I: Interner,
|
|
||||||
{
|
|
||||||
fn span(&self) -> I::Span;
|
|
||||||
|
|
||||||
fn param_env(&self) -> I::ParamEnv;
|
|
||||||
|
|
||||||
/// Whether aliases should be related structurally. This is pretty much
|
|
||||||
/// always `No` unless you're equating in some specific locations of the
|
|
||||||
/// new solver. See the comments in these use-cases for more details.
|
|
||||||
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
|
|
||||||
|
|
||||||
/// Register obligations that must hold in order for this relation to hold
|
|
||||||
fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>);
|
|
||||||
|
|
||||||
/// Register predicates that must hold in order for this relation to hold.
|
|
||||||
/// This uses the default `param_env` of the obligation.
|
|
||||||
fn register_predicates(
|
|
||||||
&mut self,
|
|
||||||
obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Register `AliasRelate` obligation(s) that both types must be related to each other.
|
|
||||||
fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty);
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
use crate::fold::TypeFoldable;
|
use crate::fold::TypeFoldable;
|
||||||
use crate::relate::Relate;
|
use crate::relate::combine::PredicateEmittingRelation;
|
||||||
|
use crate::relate::{Relate, RelateResult};
|
||||||
use crate::solve::{Goal, NoSolution, SolverMode};
|
use crate::solve::{Goal, NoSolution, SolverMode};
|
||||||
use crate::{self as ty, Interner};
|
use crate::{self as ty, Interner};
|
||||||
|
|
||||||
@ -7,6 +8,14 @@ pub trait InferCtxtLike: Sized {
|
|||||||
type Interner: Interner;
|
type Interner: Interner;
|
||||||
fn cx(&self) -> Self::Interner;
|
fn cx(&self) -> Self::Interner;
|
||||||
|
|
||||||
|
/// Whether the new trait solver is enabled. This only exists because rustc
|
||||||
|
/// shares code between the new and old trait solvers; for all other users,
|
||||||
|
/// this should always be true. If this is unknowingly false and you try to
|
||||||
|
/// use the new trait solver, things will break badly.
|
||||||
|
fn next_trait_solver(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn solver_mode(&self) -> SolverMode;
|
fn solver_mode(&self) -> SolverMode;
|
||||||
|
|
||||||
fn universe(&self) -> ty::UniverseIndex;
|
fn universe(&self) -> ty::UniverseIndex;
|
||||||
@ -58,6 +67,28 @@ pub trait InferCtxtLike: Sized {
|
|||||||
f: impl FnOnce(T) -> U,
|
f: impl FnOnce(T) -> U,
|
||||||
) -> U;
|
) -> U;
|
||||||
|
|
||||||
|
fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid);
|
||||||
|
fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid);
|
||||||
|
fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid);
|
||||||
|
fn equate_effect_vids_raw(&self, a: ty::EffectVid, b: ty::EffectVid);
|
||||||
|
|
||||||
|
fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue);
|
||||||
|
fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue);
|
||||||
|
fn instantiate_effect_var_raw(
|
||||||
|
&self,
|
||||||
|
vid: ty::EffectVid,
|
||||||
|
value: <Self::Interner as Interner>::Const,
|
||||||
|
);
|
||||||
|
fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>(
|
||||||
|
&self,
|
||||||
|
relation: &mut R,
|
||||||
|
target_is_expected: bool,
|
||||||
|
target_vid: ty::ConstVid,
|
||||||
|
source_ct: <Self::Interner as Interner>::Const,
|
||||||
|
) -> RelateResult<Self::Interner, ()>;
|
||||||
|
|
||||||
|
fn set_tainted_by_errors(&self, e: <Self::Interner as Interner>::ErrorGuaranteed);
|
||||||
|
|
||||||
fn relate<T: Relate<Self::Interner>>(
|
fn relate<T: Relate<Self::Interner>>(
|
||||||
&self,
|
&self,
|
||||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||||
@ -77,6 +108,10 @@ pub trait InferCtxtLike: Sized {
|
|||||||
&self,
|
&self,
|
||||||
ty: <Self::Interner as Interner>::Ty,
|
ty: <Self::Interner as Interner>::Ty,
|
||||||
) -> <Self::Interner as Interner>::Ty;
|
) -> <Self::Interner as Interner>::Ty;
|
||||||
|
fn shallow_resolve_const(
|
||||||
|
&self,
|
||||||
|
ty: <Self::Interner as Interner>::Const,
|
||||||
|
) -> <Self::Interner as Interner>::Const;
|
||||||
|
|
||||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||||
where
|
where
|
||||||
|
@ -9,8 +9,22 @@ use crate::fold::TypeFoldable;
|
|||||||
use crate::inherent::*;
|
use crate::inherent::*;
|
||||||
use crate::{self as ty, Interner};
|
use crate::{self as ty, Interner};
|
||||||
|
|
||||||
|
pub mod combine;
|
||||||
|
|
||||||
pub type RelateResult<I, T> = Result<T, TypeError<I>>;
|
pub type RelateResult<I, T> = Result<T, TypeError<I>>;
|
||||||
|
|
||||||
|
/// Whether aliases should be related structurally or not. Used
|
||||||
|
/// to adjust the behavior of generalization and combine.
|
||||||
|
///
|
||||||
|
/// This should always be `No` unless in a few special-cases when
|
||||||
|
/// instantiating canonical responses and in the new solver. Each
|
||||||
|
/// such case should have a comment explaining why it is used.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum StructurallyRelateAliases {
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
|
||||||
/// Extra information about why we ended up with a particular variance.
|
/// Extra information about why we ended up with a particular variance.
|
||||||
/// This is only used to add more information to error messages, and
|
/// This is only used to add more information to error messages, and
|
||||||
/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
|
/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
|
||||||
|
255
compiler/rustc_type_ir/src/relate/combine.rs
Normal file
255
compiler/rustc_type_ir/src/relate/combine.rs
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
ExpectedFound, RelateResult, StructurallyRelateAliases, TypeRelation,
|
||||||
|
structurally_relate_consts, structurally_relate_tys,
|
||||||
|
};
|
||||||
|
use crate::error::TypeError;
|
||||||
|
use crate::inherent::*;
|
||||||
|
use crate::solve::{Goal, SolverMode};
|
||||||
|
use crate::visit::TypeVisitableExt as _;
|
||||||
|
use crate::{self as ty, InferCtxtLike, Interner, Upcast};
|
||||||
|
|
||||||
|
pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>:
|
||||||
|
TypeRelation<I>
|
||||||
|
where
|
||||||
|
Infcx: InferCtxtLike<Interner = I>,
|
||||||
|
I: Interner,
|
||||||
|
{
|
||||||
|
fn span(&self) -> I::Span;
|
||||||
|
|
||||||
|
fn param_env(&self) -> I::ParamEnv;
|
||||||
|
|
||||||
|
/// Whether aliases should be related structurally. This is pretty much
|
||||||
|
/// always `No` unless you're equating in some specific locations of the
|
||||||
|
/// new solver. See the comments in these use-cases for more details.
|
||||||
|
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases;
|
||||||
|
|
||||||
|
/// Register obligations that must hold in order for this relation to hold
|
||||||
|
fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>);
|
||||||
|
|
||||||
|
/// Register predicates that must hold in order for this relation to hold.
|
||||||
|
/// This uses the default `param_env` of the obligation.
|
||||||
|
fn register_predicates(
|
||||||
|
&mut self,
|
||||||
|
obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Register `AliasRelate` obligation(s) that both types must be related to each other.
|
||||||
|
fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait InferCtxtCombineExt<I: Interner>: InferCtxtLike {
|
||||||
|
fn super_combine_tys<R>(&self, relation: &mut R, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty>
|
||||||
|
where
|
||||||
|
R: PredicateEmittingRelation<Self>;
|
||||||
|
|
||||||
|
fn super_combine_consts<R>(
|
||||||
|
&self,
|
||||||
|
relation: &mut R,
|
||||||
|
a: I::Const,
|
||||||
|
b: I::Const,
|
||||||
|
) -> RelateResult<I, I::Const>
|
||||||
|
where
|
||||||
|
R: PredicateEmittingRelation<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, Infcx: InferCtxtLike<Interner = I>> InferCtxtCombineExt<I> for Infcx {
|
||||||
|
fn super_combine_tys<R>(&self, relation: &mut R, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty>
|
||||||
|
where
|
||||||
|
R: PredicateEmittingRelation<Infcx>,
|
||||||
|
{
|
||||||
|
debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
|
||||||
|
debug_assert!(!a.has_escaping_bound_vars());
|
||||||
|
debug_assert!(!b.has_escaping_bound_vars());
|
||||||
|
|
||||||
|
match (a.kind(), b.kind()) {
|
||||||
|
(ty::Error(e), _) | (_, ty::Error(e)) => {
|
||||||
|
self.set_tainted_by_errors(e);
|
||||||
|
return Ok(Ty::new_error(self.cx(), e));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relate integral variables to other types
|
||||||
|
(ty::Infer(ty::IntVar(a_id)), ty::Infer(ty::IntVar(b_id))) => {
|
||||||
|
self.equate_int_vids_raw(a_id, b_id);
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
(ty::Infer(ty::IntVar(v_id)), ty::Int(v)) => {
|
||||||
|
self.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v));
|
||||||
|
Ok(b)
|
||||||
|
}
|
||||||
|
(ty::Int(v), ty::Infer(ty::IntVar(v_id))) => {
|
||||||
|
self.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v));
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
(ty::Infer(ty::IntVar(v_id)), ty::Uint(v)) => {
|
||||||
|
self.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v));
|
||||||
|
Ok(b)
|
||||||
|
}
|
||||||
|
(ty::Uint(v), ty::Infer(ty::IntVar(v_id))) => {
|
||||||
|
self.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v));
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relate floating-point variables to other types
|
||||||
|
(ty::Infer(ty::FloatVar(a_id)), ty::Infer(ty::FloatVar(b_id))) => {
|
||||||
|
self.equate_float_vids_raw(a_id, b_id);
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
(ty::Infer(ty::FloatVar(v_id)), ty::Float(v)) => {
|
||||||
|
self.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v));
|
||||||
|
Ok(b)
|
||||||
|
}
|
||||||
|
(ty::Float(v), ty::Infer(ty::FloatVar(v_id))) => {
|
||||||
|
self.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v));
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
|
||||||
|
(ty::Alias(..), ty::Infer(ty::TyVar(_))) | (ty::Infer(ty::TyVar(_)), ty::Alias(..))
|
||||||
|
if self.next_trait_solver() =>
|
||||||
|
{
|
||||||
|
panic!(
|
||||||
|
"We do not expect to encounter `TyVar` this late in combine \
|
||||||
|
-- they should have been handled earlier"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(_, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)))
|
||||||
|
| (ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), _)
|
||||||
|
if self.next_trait_solver() =>
|
||||||
|
{
|
||||||
|
panic!("We do not expect to encounter `Fresh` variables in the new solver")
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => {
|
||||||
|
match relation.structurally_relate_aliases() {
|
||||||
|
StructurallyRelateAliases::Yes => structurally_relate_tys(relation, a, b),
|
||||||
|
StructurallyRelateAliases::No => {
|
||||||
|
relation.register_alias_relate_predicate(a, b);
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All other cases of inference are errors
|
||||||
|
(ty::Infer(_), _) | (_, ty::Infer(_)) => {
|
||||||
|
Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
(ty::Alias(ty::Opaque, _), _) | (_, ty::Alias(ty::Opaque, _)) => {
|
||||||
|
match self.solver_mode() {
|
||||||
|
SolverMode::Normal => {
|
||||||
|
assert!(!self.next_trait_solver());
|
||||||
|
structurally_relate_tys(relation, a, b)
|
||||||
|
}
|
||||||
|
// During coherence, opaque types should be treated as *possibly*
|
||||||
|
// equal to any other type (except for possibly itself). This is an
|
||||||
|
// extremely heavy hammer, but can be relaxed in a forwards-compatible
|
||||||
|
// way later.
|
||||||
|
SolverMode::Coherence => {
|
||||||
|
relation
|
||||||
|
.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => structurally_relate_tys(relation, a, b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn super_combine_consts<R>(
|
||||||
|
&self,
|
||||||
|
relation: &mut R,
|
||||||
|
a: I::Const,
|
||||||
|
b: I::Const,
|
||||||
|
) -> RelateResult<I, I::Const>
|
||||||
|
where
|
||||||
|
R: PredicateEmittingRelation<Infcx>,
|
||||||
|
{
|
||||||
|
debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b);
|
||||||
|
debug_assert!(!a.has_escaping_bound_vars());
|
||||||
|
debug_assert!(!b.has_escaping_bound_vars());
|
||||||
|
|
||||||
|
if a == b {
|
||||||
|
return Ok(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
let a = self.shallow_resolve_const(a);
|
||||||
|
let b = self.shallow_resolve_const(b);
|
||||||
|
|
||||||
|
match (a.kind(), b.kind()) {
|
||||||
|
(
|
||||||
|
ty::ConstKind::Infer(ty::InferConst::Var(a_vid)),
|
||||||
|
ty::ConstKind::Infer(ty::InferConst::Var(b_vid)),
|
||||||
|
) => {
|
||||||
|
self.equate_const_vids_raw(a_vid, b_vid);
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
ty::ConstKind::Infer(ty::InferConst::EffectVar(a_vid)),
|
||||||
|
ty::ConstKind::Infer(ty::InferConst::EffectVar(b_vid)),
|
||||||
|
) => {
|
||||||
|
self.equate_effect_vids_raw(a_vid, b_vid);
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// All other cases of inference with other variables are errors.
|
||||||
|
(
|
||||||
|
ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)),
|
||||||
|
ty::ConstKind::Infer(_),
|
||||||
|
)
|
||||||
|
| (
|
||||||
|
ty::ConstKind::Infer(_),
|
||||||
|
ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)),
|
||||||
|
) => {
|
||||||
|
panic!(
|
||||||
|
"tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
(ty::ConstKind::Infer(ty::InferConst::Var(vid)), _) => {
|
||||||
|
self.instantiate_const_var_raw(relation, true, vid, b)?;
|
||||||
|
Ok(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, ty::ConstKind::Infer(ty::InferConst::Var(vid))) => {
|
||||||
|
self.instantiate_const_var_raw(relation, false, vid, a)?;
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
(ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)), _) => {
|
||||||
|
self.instantiate_effect_var_raw(vid, b);
|
||||||
|
Ok(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, ty::ConstKind::Infer(ty::InferConst::EffectVar(vid))) => {
|
||||||
|
self.instantiate_effect_var_raw(vid, a);
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
|
||||||
|
if self.cx().features().generic_const_exprs() || self.next_trait_solver() =>
|
||||||
|
{
|
||||||
|
match relation.structurally_relate_aliases() {
|
||||||
|
StructurallyRelateAliases::No => {
|
||||||
|
relation.register_predicates([if self.next_trait_solver() {
|
||||||
|
ty::PredicateKind::AliasRelate(
|
||||||
|
a.into(),
|
||||||
|
b.into(),
|
||||||
|
ty::AliasRelationDirection::Equate,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ty::PredicateKind::ConstEquate(a, b)
|
||||||
|
}]);
|
||||||
|
|
||||||
|
Ok(b)
|
||||||
|
}
|
||||||
|
StructurallyRelateAliases::Yes => structurally_relate_consts(relation, a, b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => structurally_relate_consts(relation, a, b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user