use std::fmt;
use std::hash::Hash;
use derive_where::derive_where;
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use crate::inherent::*;
use crate::lift::Lift;
use crate::upcast::{Upcast, UpcastFrom};
use crate::visit::TypeVisitableExt as _;
use crate::{self as ty, Interner};
#[derive_where(Clone; I: Interner, A: Clone)]
#[derive_where(Copy; I: Interner, A: Copy)]
#[derive_where(Hash; I: Interner, A: Hash)]
#[derive_where(PartialEq; I: Interner, A: PartialEq)]
#[derive_where(Eq; I: Interner, A: Eq)]
#[derive_where(Debug; I: Interner, A: fmt::Debug)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct OutlivesPredicate<I: Interner, A>(pub A, pub I::Region);
impl<I: Interner, U: Interner, A> Lift<U> for OutlivesPredicate<I, A>
where
A: Lift<U>,
I::Region: Lift<U, Lifted = U::Region>,
{
type Lifted = OutlivesPredicate<U, A::Lifted>;
fn lift_to_interner(self, cx: U) -> Option<Self::Lifted> {
Some(OutlivesPredicate(self.0.lift_to_interner(cx)?, self.1.lift_to_interner(cx)?))
}
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct TraitRef<I: Interner> {
pub def_id: I::DefId,
pub args: I::GenericArgs,
_use_trait_ref_new_instead: (),
}
impl<I: Interner> TraitRef<I> {
pub fn new_from_args(interner: I, trait_def_id: I::DefId, args: I::GenericArgs) -> Self {
interner.debug_assert_args_compatible(trait_def_id, args);
Self { def_id: trait_def_id, args, _use_trait_ref_new_instead: () }
}
pub fn new(
interner: I,
trait_def_id: I::DefId,
args: impl IntoIterator<Item: Into<I::GenericArg>>,
) -> Self {
let args = interner.mk_args_from_iter(args.into_iter().map(Into::into));
Self::new_from_args(interner, trait_def_id, args)
}
pub fn from_method(interner: I, trait_id: I::DefId, args: I::GenericArgs) -> TraitRef<I> {
let generics = interner.generics_of(trait_id);
TraitRef::new(interner, trait_id, args.iter().take(generics.count()))
}
pub fn identity(interner: I, def_id: I::DefId) -> TraitRef<I> {
TraitRef::new_from_args(
interner,
def_id,
I::GenericArgs::identity_for_item(interner, def_id),
)
}
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
TraitRef::new(
interner,
self.def_id,
[self_ty.into()].into_iter().chain(self.args.iter().skip(1)),
)
}
#[inline]
pub fn self_ty(&self) -> I::Ty {
self.args.type_at(0)
}
}
impl<I: Interner> ty::Binder<I, TraitRef<I>> {
pub fn self_ty(&self) -> ty::Binder<I, I::Ty> {
self.map_bound_ref(|tr| tr.self_ty())
}
pub fn def_id(&self) -> I::DefId {
self.skip_binder().def_id
}
pub fn to_host_effect_clause(self, cx: I, constness: BoundConstness) -> I::Clause {
self.map_bound(|trait_ref| {
ty::ClauseKind::HostEffect(HostEffectPredicate { trait_ref, constness })
})
.upcast(cx)
}
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct TraitPredicate<I: Interner> {
pub trait_ref: TraitRef<I>,
pub polarity: PredicatePolarity,
}
impl<I: Interner> TraitPredicate<I> {
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
Self { trait_ref: self.trait_ref.with_self_ty(interner, self_ty), polarity: self.polarity }
}
pub fn def_id(self) -> I::DefId {
self.trait_ref.def_id
}
pub fn self_ty(self) -> I::Ty {
self.trait_ref.self_ty()
}
}
impl<I: Interner> ty::Binder<I, TraitPredicate<I>> {
pub fn def_id(self) -> I::DefId {
self.skip_binder().def_id()
}
pub fn self_ty(self) -> ty::Binder<I, I::Ty> {
self.map_bound(|trait_ref| trait_ref.self_ty())
}
#[inline]
pub fn polarity(self) -> PredicatePolarity {
self.skip_binder().polarity
}
}
impl<I: Interner> UpcastFrom<I, TraitRef<I>> for TraitPredicate<I> {
fn upcast_from(from: TraitRef<I>, _tcx: I) -> Self {
TraitPredicate { trait_ref: from, polarity: PredicatePolarity::Positive }
}
}
impl<I: Interner> fmt::Debug for TraitPredicate<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub enum ImplPolarity {
Positive,
Negative,
Reservation,
}
impl fmt::Display for ImplPolarity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Positive => f.write_str("positive"),
Self::Negative => f.write_str("negative"),
Self::Reservation => f.write_str("reservation"),
}
}
}
impl ImplPolarity {
pub fn as_str(self) -> &'static str {
match self {
Self::Positive => "",
Self::Negative => "!",
Self::Reservation => "",
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub enum PredicatePolarity {
Positive,
Negative,
}
impl PredicatePolarity {
pub fn flip(&self) -> PredicatePolarity {
match self {
PredicatePolarity::Positive => PredicatePolarity::Negative,
PredicatePolarity::Negative => PredicatePolarity::Positive,
}
}
}
impl fmt::Display for PredicatePolarity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Positive => f.write_str("positive"),
Self::Negative => f.write_str("negative"),
}
}
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub enum ExistentialPredicate<I: Interner> {
Trait(ExistentialTraitRef<I>),
Projection(ExistentialProjection<I>),
AutoTrait(I::DefId),
}
impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> I::Clause {
match self.skip_binder() {
ExistentialPredicate::Trait(tr) => self.rebind(tr).with_self_ty(cx, self_ty).upcast(cx),
ExistentialPredicate::Projection(p) => {
self.rebind(p.with_self_ty(cx, self_ty)).upcast(cx)
}
ExistentialPredicate::AutoTrait(did) => {
let generics = cx.generics_of(did);
let trait_ref = if generics.count() == 1 {
ty::TraitRef::new(cx, did, [self_ty])
} else {
let err_args = GenericArgs::extend_with_error(cx, did, &[self_ty.into()]);
ty::TraitRef::new_from_args(cx, did, err_args)
};
self.rebind(trait_ref).upcast(cx)
}
}
}
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct ExistentialTraitRef<I: Interner> {
pub def_id: I::DefId,
pub args: I::GenericArgs,
_use_existential_trait_ref_new_instead: (),
}
impl<I: Interner> ExistentialTraitRef<I> {
pub fn new_from_args(interner: I, trait_def_id: I::DefId, args: I::GenericArgs) -> Self {
interner.debug_assert_existential_args_compatible(trait_def_id, args);
Self { def_id: trait_def_id, args, _use_existential_trait_ref_new_instead: () }
}
pub fn new(
interner: I,
trait_def_id: I::DefId,
args: impl IntoIterator<Item: Into<I::GenericArg>>,
) -> Self {
let args = interner.mk_args_from_iter(args.into_iter().map(Into::into));
Self::new_from_args(interner, trait_def_id, args)
}
pub fn erase_self_ty(interner: I, trait_ref: TraitRef<I>) -> ExistentialTraitRef<I> {
trait_ref.args.type_at(0);
ExistentialTraitRef {
def_id: trait_ref.def_id,
args: interner.mk_args(&trait_ref.args.as_slice()[1..]),
_use_existential_trait_ref_new_instead: (),
}
}
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> TraitRef<I> {
TraitRef::new(interner, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter()))
}
}
impl<I: Interner> ty::Binder<I, ExistentialTraitRef<I>> {
pub fn def_id(&self) -> I::DefId {
self.skip_binder().def_id
}
pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> ty::Binder<I, TraitRef<I>> {
self.map_bound(|trait_ref| trait_ref.with_self_ty(cx, self_ty))
}
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct ExistentialProjection<I: Interner> {
pub def_id: I::DefId,
pub args: I::GenericArgs,
pub term: I::Term,
use_existential_projection_new_instead: (),
}
impl<I: Interner> ExistentialProjection<I> {
pub fn new_from_args(
interner: I,
def_id: I::DefId,
args: I::GenericArgs,
term: I::Term,
) -> ExistentialProjection<I> {
interner.debug_assert_existential_args_compatible(def_id, args);
Self { def_id, args, term, use_existential_projection_new_instead: () }
}
pub fn new(
interner: I,
def_id: I::DefId,
args: impl IntoIterator<Item: Into<I::GenericArg>>,
term: I::Term,
) -> ExistentialProjection<I> {
let args = interner.mk_args_from_iter(args.into_iter().map(Into::into));
Self::new_from_args(interner, def_id, args, term)
}
pub fn trait_ref(&self, interner: I) -> ExistentialTraitRef<I> {
let def_id = interner.parent(self.def_id);
let args_count = interner.generics_of(def_id).count() - 1;
let args = interner.mk_args(&self.args.as_slice()[..args_count]);
ExistentialTraitRef { def_id, args, _use_existential_trait_ref_new_instead: () }
}
pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
debug_assert!(!self_ty.has_escaping_bound_vars());
ProjectionPredicate {
projection_term: AliasTerm::new(
interner,
self.def_id,
[self_ty.into()].iter().chain(self.args.iter()),
),
term: self.term,
}
}
pub fn erase_self_ty(interner: I, projection_predicate: ProjectionPredicate<I>) -> Self {
projection_predicate.projection_term.args.type_at(0);
Self {
def_id: projection_predicate.projection_term.def_id,
args: interner.mk_args(&projection_predicate.projection_term.args.as_slice()[1..]),
term: projection_predicate.term,
use_existential_projection_new_instead: (),
}
}
}
impl<I: Interner> ty::Binder<I, ExistentialProjection<I>> {
pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> ty::Binder<I, ProjectionPredicate<I>> {
self.map_bound(|p| p.with_self_ty(cx, self_ty))
}
pub fn item_def_id(&self) -> I::DefId {
self.skip_binder().def_id
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
pub enum AliasTermKind {
ProjectionTy,
InherentTy,
OpaqueTy,
WeakTy,
UnevaluatedConst,
ProjectionConst,
}
impl AliasTermKind {
pub fn descr(self) -> &'static str {
match self {
AliasTermKind::ProjectionTy => "associated type",
AliasTermKind::ProjectionConst => "associated const",
AliasTermKind::InherentTy => "inherent associated type",
AliasTermKind::OpaqueTy => "opaque type",
AliasTermKind::WeakTy => "type alias",
AliasTermKind::UnevaluatedConst => "unevaluated constant",
}
}
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct AliasTerm<I: Interner> {
pub args: I::GenericArgs,
pub def_id: I::DefId,
#[derive_where(skip(Debug))]
_use_alias_term_new_instead: (),
}
impl<I: Interner> AliasTerm<I> {
pub fn new_from_args(interner: I, def_id: I::DefId, args: I::GenericArgs) -> AliasTerm<I> {
interner.debug_assert_args_compatible(def_id, args);
AliasTerm { def_id, args, _use_alias_term_new_instead: () }
}
pub fn new(
interner: I,
def_id: I::DefId,
args: impl IntoIterator<Item: Into<I::GenericArg>>,
) -> AliasTerm<I> {
let args = interner.mk_args_from_iter(args.into_iter().map(Into::into));
Self::new_from_args(interner, def_id, args)
}
pub fn expect_ty(self, interner: I) -> ty::AliasTy<I> {
match self.kind(interner) {
AliasTermKind::ProjectionTy
| AliasTermKind::InherentTy
| AliasTermKind::OpaqueTy
| AliasTermKind::WeakTy => {}
AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
panic!("Cannot turn `UnevaluatedConst` into `AliasTy`")
}
}
ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }
}
pub fn kind(self, interner: I) -> AliasTermKind {
interner.alias_term_kind(self)
}
pub fn to_term(self, interner: I) -> I::Term {
match self.kind(interner) {
AliasTermKind::ProjectionTy => {
Ty::new_alias(interner, ty::AliasTyKind::Projection, ty::AliasTy {
def_id: self.def_id,
args: self.args,
_use_alias_ty_new_instead: (),
})
.into()
}
AliasTermKind::InherentTy => {
Ty::new_alias(interner, ty::AliasTyKind::Inherent, ty::AliasTy {
def_id: self.def_id,
args: self.args,
_use_alias_ty_new_instead: (),
})
.into()
}
AliasTermKind::OpaqueTy => {
Ty::new_alias(interner, ty::AliasTyKind::Opaque, ty::AliasTy {
def_id: self.def_id,
args: self.args,
_use_alias_ty_new_instead: (),
})
.into()
}
AliasTermKind::WeakTy => Ty::new_alias(interner, ty::AliasTyKind::Weak, ty::AliasTy {
def_id: self.def_id,
args: self.args,
_use_alias_ty_new_instead: (),
})
.into(),
AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
I::Const::new_unevaluated(
interner,
ty::UnevaluatedConst::new(self.def_id, self.args),
)
.into()
}
}
}
}
impl<I: Interner> AliasTerm<I> {
pub fn self_ty(self) -> I::Ty {
self.args.type_at(0)
}
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
AliasTerm::new(
interner,
self.def_id,
[self_ty.into()].into_iter().chain(self.args.iter().skip(1)),
)
}
pub fn trait_def_id(self, interner: I) -> I::DefId {
assert!(
matches!(
self.kind(interner),
AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst
),
"expected a projection"
);
interner.parent(self.def_id)
}
pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::GenericArgsSlice) {
interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
}
pub fn trait_ref(self, interner: I) -> TraitRef<I> {
self.trait_ref_and_own_args(interner).0
}
}
impl<I: Interner> From<ty::AliasTy<I>> for AliasTerm<I> {
fn from(ty: ty::AliasTy<I>) -> Self {
AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () }
}
}
impl<I: Interner> From<ty::UnevaluatedConst<I>> for AliasTerm<I> {
fn from(ct: ty::UnevaluatedConst<I>) -> Self {
AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () }
}
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct ProjectionPredicate<I: Interner> {
pub projection_term: AliasTerm<I>,
pub term: I::Term,
}
impl<I: Interner> ProjectionPredicate<I> {
pub fn self_ty(self) -> I::Ty {
self.projection_term.self_ty()
}
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
Self { projection_term: self.projection_term.with_self_ty(interner, self_ty), ..self }
}
pub fn trait_def_id(self, interner: I) -> I::DefId {
self.projection_term.trait_def_id(interner)
}
pub fn def_id(self) -> I::DefId {
self.projection_term.def_id
}
}
impl<I: Interner> ty::Binder<I, ProjectionPredicate<I>> {
#[inline]
pub fn trait_def_id(&self, cx: I) -> I::DefId {
self.skip_binder().projection_term.trait_def_id(cx)
}
pub fn term(&self) -> ty::Binder<I, I::Term> {
self.map_bound(|predicate| predicate.term)
}
pub fn item_def_id(&self) -> I::DefId {
self.skip_binder().projection_term.def_id
}
}
impl<I: Interner> fmt::Debug for ProjectionPredicate<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_term, self.term)
}
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct NormalizesTo<I: Interner> {
pub alias: AliasTerm<I>,
pub term: I::Term,
}
impl<I: Interner> NormalizesTo<I> {
pub fn self_ty(self) -> I::Ty {
self.alias.self_ty()
}
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo<I> {
Self { alias: self.alias.with_self_ty(interner, self_ty), ..self }
}
pub fn trait_def_id(self, interner: I) -> I::DefId {
self.alias.trait_def_id(interner)
}
pub fn def_id(self) -> I::DefId {
self.alias.def_id
}
}
impl<I: Interner> fmt::Debug for NormalizesTo<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "NormalizesTo({:?}, {:?})", self.alias, self.term)
}
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub struct HostEffectPredicate<I: Interner> {
pub trait_ref: ty::TraitRef<I>,
pub constness: BoundConstness,
}
impl<I: Interner> HostEffectPredicate<I> {
pub fn self_ty(self) -> I::Ty {
self.trait_ref.self_ty()
}
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
Self { trait_ref: self.trait_ref.with_self_ty(interner, self_ty), ..self }
}
pub fn def_id(self) -> I::DefId {
self.trait_ref.def_id
}
}
impl<I: Interner> ty::Binder<I, HostEffectPredicate<I>> {
pub fn def_id(self) -> I::DefId {
self.skip_binder().def_id()
}
pub fn self_ty(self) -> ty::Binder<I, I::Ty> {
self.map_bound(|trait_ref| trait_ref.self_ty())
}
#[inline]
pub fn constness(self) -> BoundConstness {
self.skip_binder().constness
}
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct SubtypePredicate<I: Interner> {
pub a_is_expected: bool,
pub a: I::Ty,
pub b: I::Ty,
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct CoercePredicate<I: Interner> {
pub a: I::Ty,
pub b: I::Ty,
}
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub enum BoundConstness {
Const,
Maybe,
}
impl BoundConstness {
pub fn satisfies(self, goal: BoundConstness) -> bool {
match (self, goal) {
(BoundConstness::Const, BoundConstness::Const | BoundConstness::Maybe) => true,
(BoundConstness::Maybe, BoundConstness::Maybe) => true,
(BoundConstness::Maybe, BoundConstness::Const) => false,
}
}
pub fn as_str(self) -> &'static str {
match self {
Self::Const => "const",
Self::Maybe => "~const",
}
}
}
impl fmt::Display for BoundConstness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Const => f.write_str("const"),
Self::Maybe => f.write_str("~const"),
}
}
}