//! Higher-ranked traits and types. //! //! A higher-ranked type is a type that needs a lifetime to be "complete". Consider the following //! code. //! ```rs //! type IntBorrow<'a> = &'a i32; //! ``` //! What if we could pass just `IntBorrow` around as a type; without it's lifetime. //! In Rust syntax, this type would be `for<'a> IntBorrow<'a>`. `'a` can be filled in with any //! lifetime. Sadly, Rust only allows `for<'a>` in trait objects. However, trait object provide //! enough for us to implement arbitrary hifher-ranked types with some extra effort. //! //! In this module the [`bijective_higher_ranked_type!`] macro generates a type that needs a lifetime to //! be complete. Before a higher-ranked type can be generated we need a higher-ranked trait to //! describe what behavior the resulting "true" type will have. //! //! The [`bijective_higher_ranked_trait!`] macro cgenerates a trait that can be used with //! [`bijective_higher_ranked_type!`] and as a bound by code wanting to accept a higher ranked type. //! Bounding a generic by a higher-ranked trait simultaniously allows any higher-ranked type with //! a "true" type with the required traits and any lifetime to be given to that "true" type. use core::marker::PhantomData; #[derive(Debug, Default, Copy, Clone, SendSync)] #[repr(transparent)] pub struct Invariant<'a>(PhantomData &'a ()>); impl<'a> Invariant<'a> { pub const NEW: Self = Self(PhantomData); } #[derive(Debug, Default, Copy, Clone, SendSync)] #[repr(transparent)] pub struct CovariantLt<'a>(PhantomData<&'a ()>); impl<'a> CovariantLt<'a> { pub const NEW: Self = Self(PhantomData); } #[derive(SendSync)] #[repr(transparent)] pub struct Marker(PhantomData *const T>); impl Marker { pub const NEW: Self = Self(PhantomData); } #[derive(Debug, Default, Copy, Clone, SendSync)] #[repr(transparent)] pub struct BorrowsCtx<'lt, 'ctx>(PhantomData<&'lt &'ctx ()>); impl<'lt, 'ctx> BorrowsCtx<'lt, 'ctx> { pub const NEW: Self = Self(PhantomData); } #[derive(Debug, Default, Copy, Clone, SendSync)] #[repr(transparent)] pub struct ImpliedBound<'short, 'long>(PhantomData<&'short &'long ()>); impl<'short, 'long> ImpliedBound<'short, 'long> { pub const NEW: Self = Self(PhantomData); } impl Copy for Marker {} impl Clone for Marker { fn clone(&self) -> Self { *self } } impl core::fmt::Debug for Marker { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("Marker").finish() } } impl Default for Marker { fn default() -> Self { Self(PhantomData) } } #[doc(hidden)] #[macro_export] macro_rules! higher_ranked_trait { { $vis:vis type class $name:ident$([$($generic:tt)*])? for<$($lt:lifetime),+> <$($for_lt:lifetime),+> { type Bound = $bound:ty; type T: {$($lower:tt)*} $(where {$($lower_where:tt)*})?; type HigherRanked: {$($higher:tt)*} $(where {$($higher_where:tt)*})?; } } => { $vis mod $name { #![allow(non_snake_case)] #[allow(unused)] use super::*; pub trait LowerForLt<$($lt,)+ $($($generic)*,)? B> where $($($lower_where)*)? $($($higher_where)*)? { type T: RaiseForLt<$($lt,)+ $($($generic)*,)? B, HigherRanked = Self> + for<$($for_lt),+> RaiseForLt<$($for_lt,)+ $($($generic)*,)? Bound<$($for_lt,)+ $($($generic)*)?>> + ?Sized + $($lower)*; } pub trait RaiseForLt<$($lt,)+ $($($generic)*,)? B> where $($($lower_where)*)? $($($higher_where)*)? { type HigherRanked: LowerForLt<$($lt,)+ $($($generic)*,)? B, T = Self> + for<$($for_lt),+> LowerForLt<$($for_lt,)+ $($($generic)*,)? Bound<$($for_lt,)+ $($($generic)*)?>> + ?Sized + $($higher)*; } pub type Bound<$($lt,)+ $($($generic)*)?> = $bound; pub trait MemberType$(<$($generic)*>)?: for<$($lt,)+> LowerForLt<$($lt,)+ $($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>> + $($higher)* $(where $($higher_where)*)? {} impl<$($($generic)*,)? __: ?Sized> MemberType$(<$($generic)*>)? for __ where __: for<$($lt,)+> LowerForLt<$($lt,)+ $($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>> + $($higher)?, $($($higher_where)*)? {} pub trait LowerType<$($lt,)+ $($($generic)*)?>: RaiseForLt<$($lt,)+ $($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>> + $($lower)* where $($($lower_where)*)? $($($higher_where)*)? {} impl<$($lt,)+ $($($generic)*,)? __: ?Sized> LowerType<$($lt,)+ $($($generic)*)?> for __ where __: RaiseForLt<$($lt,)+ $($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>> + $($lower)*, $($($lower_where)*)? $($($higher_where)*)? {} pub type T<$($lt,)+ $($($generic)*,)? __> = <__ as LowerForLt<$($lt,)+ $($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>>>::T; pub type HigherRanked<$($lt,)+ $($($generic)*,)? __> = <__ as RaiseForLt<$($lt,)+ $($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>>>::HigherRanked; // // pub type HigherRankedAll<$($lt,)+ $($($generic)*,)? __> = // <__ as RaiseForLtAll<$($($generic)*,)? Bound<$($lt,)+ $($($generic)*)?>>>::HigherRankedAll; } } } use effectful::SendSync; pub use higher_ranked_trait; #[doc(hidden)] #[macro_export] macro_rules! higher_ranked_type { { impl $higher_trait:ident { impl$([$($lower_generic:tt)*])? type T[$($lower_forward:tt)*] for $lower_higher:ty = $lower:ty $(where {$($lower_where:tt)*})?; impl$([$($higher_generic:tt)*])? type HigherRanked[$($higher_lt:lifetime),+]$([$($higher_forward:tt)*])? for $higher_lower:ty = $higher:ty $(where {$($higher_where:tt)*})?; // // impl$([$($higher_all_generic:tt)*])? type HigherRankedAll[$($higher_all_lt:lifetime),+]$([$($higher_all_forward:tt)*])? for $higher_all_lower:ty = // $higher_all:ty // $(where {$($higher_all_where:tt)*})?; } } => { impl$(<$($lower_generic)*>)* $higher_trait::LowerForLt<$($lower_forward)*, $higher_trait::Bound<$($lower_forward)*>> for $lower_higher $(where $($lower_where)*)? { type T = $lower; } impl$(<$($higher_generic)*>)* $higher_trait::RaiseForLt<$($higher_lt,)+ $($($higher_forward)*,)? $higher_trait::Bound<$($higher_lt,)+ $($($higher_forward)*)?>> for $higher_lower $(where $($higher_where)*)? { type HigherRanked = $higher; } // // impl$(<$($higher_all_generic)*>)* $higher_trait::RaiseForLtAll<$($($higher_all_forward)*,)? $higher_trait::Bound<$($higher_all_lt,)+ $($($higher_all_forward)*)?>> for $higher_all_lower // $(where $($higher_all_where)*)? // { // type HigherRankedAll = $higher_all; // } } } pub use higher_ranked_type; // #[cfg(test)] // mod test { // use super::*; // // /// Some trait with two lifetimes and a generic. // trait Demo<'lt, 'ctx, T: Send + 'lt> { // fn add(&self, x: &'lt &'ctx i32) -> i32; // } // // impl<'lt, 'ctx, T: Send + 'lt> Demo<'lt, 'ctx, T> for i32 { // fn add(&self, x: &'lt &'ctx i32) -> i32 { // self + **x // } // } // // impl<'lt, 'ctx, T: Send + 'lt> Demo<'lt, 'ctx, T> for &'lt (dyn Demo<'lt, 'ctx, T> + 'lt) { // fn add(&self, x: &'lt &'ctx i32) -> i32 { // (**self).add(x) // } // } // // // Higher-ranked trait that requires the "true" type to implement Demo. // bijective_higher_ranked_trait! { // type class Any['ctx, T]: [for<'lt> Demo<'lt, 'ctx, T>] // where { // T: Send, // } // for where { // T: 'lt // } // } // // // Higher-ranked type with a "true" type of a borrow of a trait object. // // The complex part to support here is the `+ 'lt`. // // This entire module is specialized to support this usecase because that is what treaty needs // // for it's API. // higher_ranked_type! { // type X['ctx, T]: (Any)[T] // where { // T: Send, // } = for<'lt> &'lt (dyn Demo<'lt, 'ctx, T> + 'lt) // } // // // We bound the generic T by the higher-ranked trait Any. // // // // We then inject a 'lt into the higher-ranked type to get a "true" type. // fn demo<'lt, 'ctx, T: Any::Trait<'ctx, i32>>(x: Any::T<'lt, 'ctx, T, i32>, y: &'lt &'ctx i32) { // assert_eq!(x.add(y), 10); // } // // #[test] // fn can_use_hkt() { // let ctx = 2; // let ctx = &ctx; // // { // // The lifetimes here can't be 'static because local isn't static even though z could be. // let local = &ctx; // let z: &dyn Demo<'_, '_, i32> = &8i32; // demo::>(z, local); // } // } // }