Skip to content

Instantly share code, notes, and snippets.

@AcrylicShrimp
Last active June 28, 2023 13:17
Show Gist options
  • Save AcrylicShrimp/9677f9874a49b5b90a7e1efec562777b to your computer and use it in GitHub Desktop.
Save AcrylicShrimp/9677f9874a49b5b90a7e1efec562777b to your computer and use it in GitHub Desktop.
Rust HKT(Higher-Kinded Type) Solution
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TypeDispatchKind {
Bool,
Int,
}
// From LLVM
pub struct BoolValue<'ctx> {
pub value: bool,
_phantom: std::marker::PhantomData<&'ctx ()>,
}
// From LLVM
pub struct IntValue<'ctx> {
pub value: i32,
_phantom: std::marker::PhantomData<&'ctx ()>,
}
pub enum BasicValueEnum<'ctx> {
Bool(BoolValue<'ctx>),
Int(IntValue<'ctx>),
}
impl<'ctx> BasicValueEnum<'ctx> {
pub fn into_bool_value(self) -> BoolValue<'ctx> {
match self {
Self::Bool(value) => value,
_ => panic!("Expected bool value"),
}
}
pub fn into_int_value(self) -> IntValue<'ctx> {
match self {
Self::Int(value) => value,
_ => panic!("Expected int value"),
}
}
}
pub trait IntoLLVM<'ctx>: Sized {
const DISPATCH_KIND: TypeDispatchKind;
fn into_llvm(value: BasicValueEnum<'ctx>) -> Self;
}
pub struct LLVMBool<'ctx> {
pub value: BoolValue<'ctx>,
}
impl<'ctx> IntoLLVM<'ctx> for LLVMBool<'ctx> {
const DISPATCH_KIND: TypeDispatchKind = TypeDispatchKind::Bool;
fn into_llvm(value: BasicValueEnum<'ctx>) -> Self {
Self {
value: value.into_bool_value(),
}
}
}
pub struct LLVMInt<'ctx> {
pub value: IntValue<'ctx>,
}
impl<'ctx> IntoLLVM<'ctx> for LLVMInt<'ctx> {
const DISPATCH_KIND: TypeDispatchKind = TypeDispatchKind::Int;
fn into_llvm(value: BasicValueEnum<'ctx>) -> Self {
Self {
value: value.into_int_value(),
}
}
}
// Contains LLVM context and other things
pub struct Context<'ctx> {
_phantom: std::marker::PhantomData<&'ctx ()>,
}
pub trait BinaryOpAccepter<L, R>
where
L: for<'ctx> IntoLLVM<'ctx>,
R: for<'ctx> IntoLLVM<'ctx>,
{
fn accept<'a, 'ctx>(
&self,
ctx: &Context<'ctx>,
lhs: BasicValueEnum<'ctx>,
rhs: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx>;
}
impl<T, L, R> BinaryOpAccepter<L, R> for T
where
T: for<'ctx> Fn(&Context<'ctx>, L, R) -> BasicValueEnum<'ctx>,
L: for<'ctx> IntoLLVM<'ctx>,
R: for<'ctx> IntoLLVM<'ctx>,
{
fn accept<'ctx>(
&self,
ctx: &Context<'ctx>,
lhs: BasicValueEnum<'ctx>,
rhs: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
self(ctx, L::into_llvm(lhs), R::into_llvm(rhs))
}
}
pub struct BinaryOpDispatcher {
dispatcher: Box<
dyn for<'ctx> Fn(
&Context<'ctx>,
BasicValueEnum<'ctx>,
BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx>,
>,
}
impl BinaryOpDispatcher {
pub fn new<T, L, R>(accepter: T) -> Self
where
T: BinaryOpAccepter<L, R> + 'static,
L: for<'c> IntoLLVM<'c>,
R: for<'c> IntoLLVM<'c>,
{
Self {
dispatcher: Box::new(
move |ctx: &Context, lhs: BasicValueEnum, rhs: BasicValueEnum| {
accepter.accept(ctx, lhs, rhs)
},
),
}
}
pub fn dispatch<'ctx>(
&self,
ctx: &Context<'ctx>,
lhs: BasicValueEnum<'ctx>,
rhs: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
(self.dispatcher)(ctx, lhs, rhs)
}
}
fn eq_bool_int<'ctx>(
ctx: &Context<'ctx>,
lhs: LLVMBool<'ctx>,
rhs: LLVMInt<'ctx>,
) -> BasicValueEnum<'ctx> {
todo!()
}
fn main() {
let eq = BinaryOpDispatcher::new(eq_bool_int);
let ctx = Context {
_phantom: std::marker::PhantomData,
};
let lhs = BasicValueEnum::Bool(BoolValue {
value: true,
_phantom: std::marker::PhantomData,
});
let rhs = BasicValueEnum::Int(IntValue {
value: 42,
_phantom: std::marker::PhantomData,
});
eq.dispatch(&ctx, lhs, rhs);
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TypeDispatchKind {
Bool,
Int,
}
// From LLVM
pub struct BoolValue<'ctx> {
pub value: bool,
_phantom: std::marker::PhantomData<&'ctx ()>,
}
// From LLVM
pub struct IntValue<'ctx> {
pub value: i32,
_phantom: std::marker::PhantomData<&'ctx ()>,
}
pub enum BasicValueEnum<'ctx> {
Bool(BoolValue<'ctx>),
Int(IntValue<'ctx>),
}
impl<'ctx> BasicValueEnum<'ctx> {
pub fn into_bool_value(self) -> BoolValue<'ctx> {
match self {
Self::Bool(value) => value,
_ => panic!("Expected bool value"),
}
}
pub fn into_int_value(self) -> IntValue<'ctx> {
match self {
Self::Int(value) => value,
_ => panic!("Expected int value"),
}
}
}
pub trait IntoLLVM {
type Of<'ctx>;
const DISPATCH_KIND: TypeDispatchKind;
fn into_llvm<'ctx>(value: BasicValueEnum<'ctx>) -> Self::Of<'ctx>;
}
pub struct LLVMBool<'ctx> {
pub value: BoolValue<'ctx>,
}
impl IntoLLVM for LLVMBool<'static> {
type Of<'ctx> = LLVMBool<'ctx>;
const DISPATCH_KIND: TypeDispatchKind = TypeDispatchKind::Bool;
fn into_llvm<'ctx>(value: BasicValueEnum<'ctx>) -> Self::Of<'ctx> {
LLVMBool {
value: value.into_bool_value(),
}
}
}
pub struct LLVMInt<'ctx> {
pub value: IntValue<'ctx>,
}
impl IntoLLVM for LLVMInt<'static> {
type Of<'ctx> = LLVMInt<'ctx>;
const DISPATCH_KIND: TypeDispatchKind = TypeDispatchKind::Int;
fn into_llvm<'ctx>(value: BasicValueEnum<'ctx>) -> Self::Of<'ctx> {
LLVMInt {
value: value.into_int_value(),
}
}
}
// Contains LLVM context and other things
pub struct Context<'ctx> {
_phantom: std::marker::PhantomData<&'ctx ()>,
}
pub trait BinaryOpAccepter<L, R>
where
L: IntoLLVM,
R: IntoLLVM,
{
fn accept<'a, 'ctx>(
&self,
ctx: &Context<'ctx>,
lhs: BasicValueEnum<'ctx>,
rhs: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx>;
}
impl<T, L, R> BinaryOpAccepter<L, R> for T
where
T: for<'ctx> Fn(&Context<'ctx>, L::Of<'ctx>, R::Of<'ctx>) -> BasicValueEnum<'ctx>,
L: IntoLLVM,
R: IntoLLVM,
{
fn accept<'ctx>(
&self,
ctx: &Context<'ctx>,
lhs: BasicValueEnum<'ctx>,
rhs: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
self(ctx, L::into_llvm(lhs), R::into_llvm(rhs))
}
}
pub struct BinaryOpDispatcher {
dispatcher: Box<
dyn for<'ctx> Fn(
&Context<'ctx>,
BasicValueEnum<'ctx>,
BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx>,
>,
}
impl BinaryOpDispatcher {
pub fn new<L, R>(accepter: impl BinaryOpAccepter<L, R> + 'static) -> Self
where
L: IntoLLVM,
R: IntoLLVM,
{
Self {
dispatcher: Box::new(
move |ctx: &Context, lhs: BasicValueEnum, rhs: BasicValueEnum| {
accepter.accept(ctx, lhs, rhs)
},
),
}
}
pub fn dispatch<'ctx>(
&self,
ctx: &Context<'ctx>,
lhs: BasicValueEnum<'ctx>,
rhs: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
(self.dispatcher)(ctx, lhs, rhs)
}
}
fn eq_bool_int<'ctx>(
ctx: &Context<'ctx>,
lhs: LLVMBool<'ctx>,
rhs: LLVMInt<'ctx>,
) -> BasicValueEnum<'ctx> {
todo!()
}
fn main() {
let eq = BinaryOpDispatcher::new::<LLVMBool, LLVMInt>(eq_bool_int);
let ctx = Context {
_phantom: std::marker::PhantomData,
};
let lhs = BasicValueEnum::Bool(BoolValue {
value: true,
_phantom: std::marker::PhantomData,
});
let rhs = BasicValueEnum::Int(IntValue {
value: 42,
_phantom: std::marker::PhantomData,
});
eq.dispatch(&ctx, lhs, rhs);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment