//! Upcasts, to avoid writing out wrapper types. use crate::*; use std::marker::PhantomData; /// The `Cast` trait is used to make annoying upcasts between /// logically equivalent types that imply wrappers. For example, one /// could convert a `DomainGoal` into a `Goal` by doing: /// /// ```ignore /// let goal: Goal = domain_goal.cast(); /// ``` /// /// This is equivalent to the more explicit: /// /// ```ignore /// let goal: Goal = Goal::DomainGoal(domain_goal) /// ``` /// /// Another useful trick is the `casted()` iterator adapter, which /// casts each element in the iterator as it is produced (you must /// have the `Caster` trait in scope for that). /// /// # Invariant /// /// `Cast` imposes a key invariant. You can only implement `T: /// Cast` if both `T` and `U` have the same semantic meaning. Also, /// as part of this, they should always use the same set of free /// variables (the `Canonical` implementation, for example, relies on /// that). /// /// # Iterators /// /// If you import the `Caster` trait, you can also write `.casted()` on an /// iterator chain to cast every instance within. /// /// # Implementing Cast /// /// Do not implement `Cast` directly. Instead, implement `CastTo`. /// This split setup allows us to write `foo.cast::()` to mean /// "cast to T". pub trait Cast: Sized { /// Cast a value to type `U` using `CastTo`. fn cast(self, interner: U::Interner) -> U where Self: CastTo, U: HasInterner, { self.cast_to(interner) } } impl Cast for T {} /// The "helper" trait for `cast` that actually implements the /// transformations. You can also use this if you want to have /// functions that take (e.g.) an `impl CastTo>` or something /// like that. pub trait CastTo: Sized { /// Cast a value to type `T`. fn cast_to(self, interner: T::Interner) -> T; } macro_rules! reflexive_impl { (for($($t:tt)*) $u:ty) => { impl<$($t)*> CastTo<$u> for $u { fn cast_to(self, _interner: <$u as HasInterner>::Interner) -> $u { self } } }; ($u:ty) => { impl CastTo<$u> for $u { fn cast_to(self, interner: <$u as HasInterner>::Interner) -> $u { self } } }; } reflexive_impl!(for(I: Interner) TyKind); reflexive_impl!(for(I: Interner) LifetimeData); reflexive_impl!(for(I: Interner) ConstData); reflexive_impl!(for(I: Interner) TraitRef); reflexive_impl!(for(I: Interner) DomainGoal); reflexive_impl!(for(I: Interner) Goal); reflexive_impl!(for(I: Interner) WhereClause); reflexive_impl!(for(I: Interner) ProgramClause); reflexive_impl!(for(I: Interner) QuantifiedWhereClause); reflexive_impl!(for(I: Interner) VariableKind); reflexive_impl!(for(I: Interner) VariableKinds); reflexive_impl!(for(I: Interner) CanonicalVarKind); reflexive_impl!(for(I: Interner) CanonicalVarKinds); reflexive_impl!(for(I: Interner) Constraint); impl CastTo> for TraitRef { fn cast_to(self, _interner: I) -> WhereClause { WhereClause::Implemented(self) } } impl CastTo> for AliasEq { fn cast_to(self, _interner: I) -> WhereClause { WhereClause::AliasEq(self) } } impl CastTo> for LifetimeOutlives { fn cast_to(self, _interner: I) -> WhereClause { WhereClause::LifetimeOutlives(self) } } impl CastTo> for TypeOutlives { fn cast_to(self, _interner: I) -> WhereClause { WhereClause::TypeOutlives(self) } } impl CastTo> for T where T: CastTo>, I: Interner, { fn cast_to(self, interner: I) -> DomainGoal { DomainGoal::Holds(self.cast(interner)) } } impl CastTo> for T where T: CastTo>, { fn cast_to(self, interner: I) -> Goal { GoalData::DomainGoal(self.cast(interner)).intern(interner) } } impl CastTo> for Normalize { fn cast_to(self, _interner: I) -> DomainGoal { DomainGoal::Normalize(self) } } impl CastTo> for WellFormed { fn cast_to(self, _interner: I) -> DomainGoal { DomainGoal::WellFormed(self) } } impl CastTo> for FromEnv { fn cast_to(self, _interner: I) -> DomainGoal { DomainGoal::FromEnv(self) } } impl CastTo> for EqGoal { fn cast_to(self, interner: I) -> Goal { GoalData::EqGoal(self).intern(interner) } } impl CastTo> for SubtypeGoal { fn cast_to(self, interner: I) -> Goal { GoalData::SubtypeGoal(self).intern(interner) } } impl + CastTo>> CastTo> for Binders { fn cast_to(self, interner: I) -> Goal { GoalData::Quantified( QuantifierKind::ForAll, self.map(|bound| bound.cast(interner)), ) .intern(interner) } } impl CastTo> for AliasTy { fn cast_to(self, _interner: I) -> TyKind { TyKind::Alias(self) } } impl CastTo> for Ty { fn cast_to(self, interner: I) -> GenericArg { GenericArg::new(interner, GenericArgData::Ty(self)) } } impl CastTo> for Lifetime { fn cast_to(self, interner: I) -> GenericArg { GenericArg::new(interner, GenericArgData::Lifetime(self)) } } impl CastTo> for Const { fn cast_to(self, interner: I) -> GenericArg { GenericArg::new(interner, GenericArgData::Const(self)) } } impl CastTo> for GenericArg { fn cast_to(self, _interner: I) -> GenericArg { self } } impl CastTo> for T where T: CastTo>, I: Interner, { fn cast_to(self, interner: I) -> ProgramClause { let implication = ProgramClauseImplication { consequence: self.cast(interner), conditions: Goals::empty(interner), constraints: Constraints::empty(interner), priority: ClausePriority::High, }; ProgramClauseData(Binders::empty(interner, implication.shifted_in(interner))) .intern(interner) } } impl CastTo> for Binders where I: Interner, T: HasInterner + CastTo>, { fn cast_to(self, interner: I) -> ProgramClause { ProgramClauseData(self.map(|bound| ProgramClauseImplication { consequence: bound.cast(interner), conditions: Goals::empty(interner), constraints: Constraints::empty(interner), priority: ClausePriority::High, })) .intern(interner) } } impl CastTo> for Option where T: CastTo, U: HasInterner, { fn cast_to(self, interner: U::Interner) -> Option { self.map(|v| v.cast(interner)) } } impl CastTo> for InEnvironment where T: HasInterner + CastTo, U: HasInterner, I: Interner, { fn cast_to(self, interner: U::Interner) -> InEnvironment { self.map(|v| v.cast(interner)) } } impl CastTo> for Result where T: CastTo, U: HasInterner, { fn cast_to(self, interner: U::Interner) -> Result { self.map(|v| v.cast(interner)) } } impl HasInterner for Option where T: HasInterner, { type Interner = T::Interner; } impl HasInterner for Result where T: HasInterner, { type Interner = T::Interner; } impl CastTo> for Canonical where T: CastTo + HasInterner, U: HasInterner, { fn cast_to(self, interner: T::Interner) -> Canonical { // Subtle point: It should be ok to re-use the binders here, // because `cast()` never introduces new inference variables, // nor changes the "substance" of the type we are working // with. It just introduces new wrapper types. Canonical { value: self.value.cast(interner), binders: self.binders.cast(interner), } } } impl CastTo> for Vec where T: CastTo + HasInterner, U: HasInterner, { fn cast_to(self, interner: U::Interner) -> Vec { self.into_iter().casted(interner).collect() } } impl CastTo for &T where T: Clone + HasInterner, { fn cast_to(self, _interner: T::Interner) -> T { self.clone() } } /// An iterator that casts each element to some other type. pub struct Casted { interner: U::Interner, iterator: IT, _cast: PhantomData, } impl Iterator for Casted where IT::Item: CastTo, U: HasInterner, { type Item = U; fn next(&mut self) -> Option { self.iterator.next().map(|item| item.cast_to(self.interner)) } fn size_hint(&self) -> (usize, Option) { self.iterator.size_hint() } } /// An iterator adapter that casts each element we are iterating over /// to some other type. pub trait Caster: Iterator + Sized { /// Cast each element in this iterator. fn casted(self, interner: U::Interner) -> Casted where Self::Item: CastTo, U: HasInterner, { Casted { interner, iterator: self, _cast: PhantomData, } } } impl Caster for I where I: Iterator {}