| use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; |
| use std::fmt; |
| use std::ops::ControlFlow; |
| |
| use crate::fold::{FallibleTypeFolder, TypeFoldable}; |
| use crate::visit::{TypeVisitable, TypeVisitor}; |
| use crate::{HashStableContext, Interner}; |
| |
| /// A clause is something that can appear in where bounds or be inferred |
| /// by implied bounds. |
| #[derive(derivative::Derivative)] |
| #[derivative(Clone(bound = ""), Hash(bound = ""))] |
| #[derive(TyEncodable, TyDecodable)] |
| pub enum ClauseKind<I: Interner> { |
| /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be |
| /// the `Self` type of the trait reference and `A`, `B`, and `C` |
| /// would be the type parameters. |
| Trait(I::TraitPredicate), |
| |
| /// `where 'a: 'b` |
| RegionOutlives(I::RegionOutlivesPredicate), |
| |
| /// `where T: 'a` |
| TypeOutlives(I::TypeOutlivesPredicate), |
| |
| /// `where <T as TraitRef>::Name == X`, approximately. |
| /// See the `ProjectionPredicate` struct for details. |
| Projection(I::ProjectionPredicate), |
| |
| /// Ensures that a const generic argument to a parameter `const N: u8` |
| /// is of type `u8`. |
| ConstArgHasType(I::Const, I::Ty), |
| |
| /// No syntax: `T` well-formed. |
| WellFormed(I::GenericArg), |
| |
| /// Constant initializer must evaluate successfully. |
| ConstEvaluatable(I::Const), |
| } |
| |
| impl<I: Interner> Copy for ClauseKind<I> |
| where |
| I::Ty: Copy, |
| I::Const: Copy, |
| I::GenericArg: Copy, |
| I::TraitPredicate: Copy, |
| I::ProjectionPredicate: Copy, |
| I::TypeOutlivesPredicate: Copy, |
| I::RegionOutlivesPredicate: Copy, |
| { |
| } |
| |
| impl<I: Interner> PartialEq for ClauseKind<I> { |
| fn eq(&self, other: &Self) -> bool { |
| match (self, other) { |
| (Self::Trait(l0), Self::Trait(r0)) => l0 == r0, |
| (Self::RegionOutlives(l0), Self::RegionOutlives(r0)) => l0 == r0, |
| (Self::TypeOutlives(l0), Self::TypeOutlives(r0)) => l0 == r0, |
| (Self::Projection(l0), Self::Projection(r0)) => l0 == r0, |
| (Self::ConstArgHasType(l0, l1), Self::ConstArgHasType(r0, r1)) => l0 == r0 && l1 == r1, |
| (Self::WellFormed(l0), Self::WellFormed(r0)) => l0 == r0, |
| (Self::ConstEvaluatable(l0), Self::ConstEvaluatable(r0)) => l0 == r0, |
| _ => false, |
| } |
| } |
| } |
| |
| impl<I: Interner> Eq for ClauseKind<I> {} |
| |
| fn clause_kind_discriminant<I: Interner>(value: &ClauseKind<I>) -> usize { |
| match value { |
| ClauseKind::Trait(_) => 0, |
| ClauseKind::RegionOutlives(_) => 1, |
| ClauseKind::TypeOutlives(_) => 2, |
| ClauseKind::Projection(_) => 3, |
| ClauseKind::ConstArgHasType(_, _) => 4, |
| ClauseKind::WellFormed(_) => 5, |
| ClauseKind::ConstEvaluatable(_) => 6, |
| } |
| } |
| |
| impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for ClauseKind<I> |
| where |
| I::Ty: HashStable<CTX>, |
| I::Const: HashStable<CTX>, |
| I::GenericArg: HashStable<CTX>, |
| I::TraitPredicate: HashStable<CTX>, |
| I::ProjectionPredicate: HashStable<CTX>, |
| I::TypeOutlivesPredicate: HashStable<CTX>, |
| I::RegionOutlivesPredicate: HashStable<CTX>, |
| { |
| fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { |
| clause_kind_discriminant(self).hash_stable(hcx, hasher); |
| match self { |
| ClauseKind::Trait(p) => p.hash_stable(hcx, hasher), |
| ClauseKind::RegionOutlives(p) => p.hash_stable(hcx, hasher), |
| ClauseKind::TypeOutlives(p) => p.hash_stable(hcx, hasher), |
| ClauseKind::Projection(p) => p.hash_stable(hcx, hasher), |
| ClauseKind::ConstArgHasType(c, t) => { |
| c.hash_stable(hcx, hasher); |
| t.hash_stable(hcx, hasher); |
| } |
| ClauseKind::WellFormed(t) => t.hash_stable(hcx, hasher), |
| ClauseKind::ConstEvaluatable(c) => c.hash_stable(hcx, hasher), |
| } |
| } |
| } |
| |
| impl<I: Interner> TypeFoldable<I> for ClauseKind<I> |
| where |
| I::Ty: TypeFoldable<I>, |
| I::Const: TypeFoldable<I>, |
| I::GenericArg: TypeFoldable<I>, |
| I::TraitPredicate: TypeFoldable<I>, |
| I::ProjectionPredicate: TypeFoldable<I>, |
| I::TypeOutlivesPredicate: TypeFoldable<I>, |
| I::RegionOutlivesPredicate: TypeFoldable<I>, |
| { |
| fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { |
| Ok(match self { |
| ClauseKind::Trait(p) => ClauseKind::Trait(p.try_fold_with(folder)?), |
| ClauseKind::RegionOutlives(p) => ClauseKind::RegionOutlives(p.try_fold_with(folder)?), |
| ClauseKind::TypeOutlives(p) => ClauseKind::TypeOutlives(p.try_fold_with(folder)?), |
| ClauseKind::Projection(p) => ClauseKind::Projection(p.try_fold_with(folder)?), |
| ClauseKind::ConstArgHasType(c, t) => { |
| ClauseKind::ConstArgHasType(c.try_fold_with(folder)?, t.try_fold_with(folder)?) |
| } |
| ClauseKind::WellFormed(p) => ClauseKind::WellFormed(p.try_fold_with(folder)?), |
| ClauseKind::ConstEvaluatable(p) => { |
| ClauseKind::ConstEvaluatable(p.try_fold_with(folder)?) |
| } |
| }) |
| } |
| } |
| |
| impl<I: Interner> TypeVisitable<I> for ClauseKind<I> |
| where |
| I::Ty: TypeVisitable<I>, |
| I::Const: TypeVisitable<I>, |
| I::GenericArg: TypeVisitable<I>, |
| I::TraitPredicate: TypeVisitable<I>, |
| I::ProjectionPredicate: TypeVisitable<I>, |
| I::TypeOutlivesPredicate: TypeVisitable<I>, |
| I::RegionOutlivesPredicate: TypeVisitable<I>, |
| { |
| fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { |
| match self { |
| ClauseKind::Trait(p) => p.visit_with(visitor), |
| ClauseKind::RegionOutlives(p) => p.visit_with(visitor), |
| ClauseKind::TypeOutlives(p) => p.visit_with(visitor), |
| ClauseKind::Projection(p) => p.visit_with(visitor), |
| ClauseKind::ConstArgHasType(c, t) => { |
| c.visit_with(visitor)?; |
| t.visit_with(visitor) |
| } |
| ClauseKind::WellFormed(p) => p.visit_with(visitor), |
| ClauseKind::ConstEvaluatable(p) => p.visit_with(visitor), |
| } |
| } |
| } |
| |
| #[derive(derivative::Derivative)] |
| #[derivative(Clone(bound = ""), Hash(bound = ""))] |
| #[derive(TyEncodable, TyDecodable)] |
| pub enum PredicateKind<I: Interner> { |
| /// Prove a clause |
| Clause(ClauseKind<I>), |
| |
| /// Trait must be object-safe. |
| ObjectSafe(I::DefId), |
| |
| /// No direct syntax. May be thought of as `where T: FnFoo<...>` |
| /// for some generic args `...` and `T` being a closure type. |
| /// Satisfied (or refuted) once we know the closure's kind. |
| ClosureKind(I::DefId, I::GenericArgs, I::ClosureKind), |
| |
| /// `T1 <: T2` |
| /// |
| /// This obligation is created most often when we have two |
| /// unresolved type variables and hence don't have enough |
| /// information to process the subtyping obligation yet. |
| Subtype(I::SubtypePredicate), |
| |
| /// `T1` coerced to `T2` |
| /// |
| /// Like a subtyping obligation, this is created most often |
| /// when we have two unresolved type variables and hence |
| /// don't have enough information to process the coercion |
| /// obligation yet. At the moment, we actually process coercions |
| /// very much like subtyping and don't handle the full coercion |
| /// logic. |
| Coerce(I::CoercePredicate), |
| |
| /// Constants must be equal. The first component is the const that is expected. |
| ConstEquate(I::Const, I::Const), |
| |
| /// A marker predicate that is always ambiguous. |
| /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous. |
| Ambiguous, |
| |
| /// Separate from `ClauseKind::Projection` which is used for normalization in new solver. |
| /// This predicate requires two terms to be equal to eachother. |
| /// |
| /// Only used for new solver |
| AliasRelate(I::Term, I::Term, AliasRelationDirection), |
| } |
| |
| impl<I: Interner> Copy for PredicateKind<I> |
| where |
| I::DefId: Copy, |
| I::Const: Copy, |
| I::GenericArgs: Copy, |
| I::Term: Copy, |
| I::CoercePredicate: Copy, |
| I::SubtypePredicate: Copy, |
| I::ClosureKind: Copy, |
| ClauseKind<I>: Copy, |
| { |
| } |
| |
| impl<I: Interner> PartialEq for PredicateKind<I> { |
| fn eq(&self, other: &Self) -> bool { |
| match (self, other) { |
| (Self::Clause(l0), Self::Clause(r0)) => l0 == r0, |
| (Self::ObjectSafe(l0), Self::ObjectSafe(r0)) => l0 == r0, |
| (Self::ClosureKind(l0, l1, l2), Self::ClosureKind(r0, r1, r2)) => { |
| l0 == r0 && l1 == r1 && l2 == r2 |
| } |
| (Self::Subtype(l0), Self::Subtype(r0)) => l0 == r0, |
| (Self::Coerce(l0), Self::Coerce(r0)) => l0 == r0, |
| (Self::ConstEquate(l0, l1), Self::ConstEquate(r0, r1)) => l0 == r0 && l1 == r1, |
| (Self::AliasRelate(l0, l1, l2), Self::AliasRelate(r0, r1, r2)) => { |
| l0 == r0 && l1 == r1 && l2 == r2 |
| } |
| _ => core::mem::discriminant(self) == core::mem::discriminant(other), |
| } |
| } |
| } |
| |
| impl<I: Interner> Eq for PredicateKind<I> {} |
| |
| fn predicate_kind_discriminant<I: Interner>(value: &PredicateKind<I>) -> usize { |
| match value { |
| PredicateKind::Clause(_) => 0, |
| PredicateKind::ObjectSafe(_) => 1, |
| PredicateKind::ClosureKind(_, _, _) => 2, |
| PredicateKind::Subtype(_) => 3, |
| PredicateKind::Coerce(_) => 4, |
| PredicateKind::ConstEquate(_, _) => 5, |
| PredicateKind::Ambiguous => 6, |
| PredicateKind::AliasRelate(_, _, _) => 7, |
| } |
| } |
| |
| impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for PredicateKind<I> |
| where |
| I::DefId: HashStable<CTX>, |
| I::Const: HashStable<CTX>, |
| I::GenericArgs: HashStable<CTX>, |
| I::Term: HashStable<CTX>, |
| I::CoercePredicate: HashStable<CTX>, |
| I::SubtypePredicate: HashStable<CTX>, |
| I::ClosureKind: HashStable<CTX>, |
| ClauseKind<I>: HashStable<CTX>, |
| { |
| fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { |
| predicate_kind_discriminant(self).hash_stable(hcx, hasher); |
| match self { |
| PredicateKind::Clause(p) => p.hash_stable(hcx, hasher), |
| PredicateKind::ObjectSafe(d) => d.hash_stable(hcx, hasher), |
| PredicateKind::ClosureKind(d, g, k) => { |
| d.hash_stable(hcx, hasher); |
| g.hash_stable(hcx, hasher); |
| k.hash_stable(hcx, hasher); |
| } |
| PredicateKind::Subtype(p) => p.hash_stable(hcx, hasher), |
| PredicateKind::Coerce(p) => p.hash_stable(hcx, hasher), |
| PredicateKind::ConstEquate(c1, c2) => { |
| c1.hash_stable(hcx, hasher); |
| c2.hash_stable(hcx, hasher); |
| } |
| PredicateKind::Ambiguous => {} |
| PredicateKind::AliasRelate(t1, t2, r) => { |
| t1.hash_stable(hcx, hasher); |
| t2.hash_stable(hcx, hasher); |
| r.hash_stable(hcx, hasher); |
| } |
| } |
| } |
| } |
| |
| impl<I: Interner> TypeFoldable<I> for PredicateKind<I> |
| where |
| I::DefId: TypeFoldable<I>, |
| I::Const: TypeFoldable<I>, |
| I::GenericArgs: TypeFoldable<I>, |
| I::Term: TypeFoldable<I>, |
| I::CoercePredicate: TypeFoldable<I>, |
| I::SubtypePredicate: TypeFoldable<I>, |
| I::ClosureKind: TypeFoldable<I>, |
| ClauseKind<I>: TypeFoldable<I>, |
| { |
| fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { |
| Ok(match self { |
| PredicateKind::Clause(c) => PredicateKind::Clause(c.try_fold_with(folder)?), |
| PredicateKind::ObjectSafe(d) => PredicateKind::ObjectSafe(d.try_fold_with(folder)?), |
| PredicateKind::ClosureKind(d, g, k) => PredicateKind::ClosureKind( |
| d.try_fold_with(folder)?, |
| g.try_fold_with(folder)?, |
| k.try_fold_with(folder)?, |
| ), |
| PredicateKind::Subtype(s) => PredicateKind::Subtype(s.try_fold_with(folder)?), |
| PredicateKind::Coerce(s) => PredicateKind::Coerce(s.try_fold_with(folder)?), |
| PredicateKind::ConstEquate(a, b) => { |
| PredicateKind::ConstEquate(a.try_fold_with(folder)?, b.try_fold_with(folder)?) |
| } |
| PredicateKind::Ambiguous => PredicateKind::Ambiguous, |
| PredicateKind::AliasRelate(a, b, d) => PredicateKind::AliasRelate( |
| a.try_fold_with(folder)?, |
| b.try_fold_with(folder)?, |
| d.try_fold_with(folder)?, |
| ), |
| }) |
| } |
| } |
| |
| impl<I: Interner> TypeVisitable<I> for PredicateKind<I> |
| where |
| I::DefId: TypeVisitable<I>, |
| I::Const: TypeVisitable<I>, |
| I::GenericArgs: TypeVisitable<I>, |
| I::Term: TypeVisitable<I>, |
| I::CoercePredicate: TypeVisitable<I>, |
| I::SubtypePredicate: TypeVisitable<I>, |
| I::ClosureKind: TypeVisitable<I>, |
| ClauseKind<I>: TypeVisitable<I>, |
| { |
| fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { |
| match self { |
| PredicateKind::Clause(p) => p.visit_with(visitor), |
| PredicateKind::ObjectSafe(d) => d.visit_with(visitor), |
| PredicateKind::ClosureKind(d, g, k) => { |
| d.visit_with(visitor)?; |
| g.visit_with(visitor)?; |
| k.visit_with(visitor) |
| } |
| PredicateKind::Subtype(s) => s.visit_with(visitor), |
| PredicateKind::Coerce(s) => s.visit_with(visitor), |
| PredicateKind::ConstEquate(a, b) => { |
| a.visit_with(visitor)?; |
| b.visit_with(visitor) |
| } |
| PredicateKind::Ambiguous => ControlFlow::Continue(()), |
| PredicateKind::AliasRelate(a, b, d) => { |
| a.visit_with(visitor)?; |
| b.visit_with(visitor)?; |
| d.visit_with(visitor) |
| } |
| } |
| } |
| } |
| |
| #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] |
| #[derive(HashStable_Generic, Encodable, Decodable)] |
| pub enum AliasRelationDirection { |
| Equate, |
| Subtype, |
| } |
| |
| impl std::fmt::Display for AliasRelationDirection { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| match self { |
| AliasRelationDirection::Equate => write!(f, "=="), |
| AliasRelationDirection::Subtype => write!(f, "<:"), |
| } |
| } |
| } |
| |
| // FIXME: Convert to DebugWithInfcx impl |
| impl<I: Interner> fmt::Debug for ClauseKind<I> { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| match self { |
| ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"), |
| ClauseKind::Trait(a) => a.fmt(f), |
| ClauseKind::RegionOutlives(pair) => pair.fmt(f), |
| ClauseKind::TypeOutlives(pair) => pair.fmt(f), |
| ClauseKind::Projection(pair) => pair.fmt(f), |
| ClauseKind::WellFormed(data) => write!(f, "WellFormed({data:?})"), |
| ClauseKind::ConstEvaluatable(ct) => { |
| write!(f, "ConstEvaluatable({ct:?})") |
| } |
| } |
| } |
| } |
| |
| // FIXME: Convert to DebugWithInfcx impl |
| impl<I: Interner> fmt::Debug for PredicateKind<I> { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| match self { |
| PredicateKind::Clause(a) => a.fmt(f), |
| PredicateKind::Subtype(pair) => pair.fmt(f), |
| PredicateKind::Coerce(pair) => pair.fmt(f), |
| PredicateKind::ObjectSafe(trait_def_id) => { |
| write!(f, "ObjectSafe({trait_def_id:?})") |
| } |
| PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => { |
| write!(f, "ClosureKind({closure_def_id:?}, {closure_args:?}, {kind:?})") |
| } |
| PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({c1:?}, {c2:?})"), |
| PredicateKind::Ambiguous => write!(f, "Ambiguous"), |
| PredicateKind::AliasRelate(t1, t2, dir) => { |
| write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})") |
| } |
| } |
| } |
| } |