WIP adding runtime-evaluated generic parameters
All checks were successful
/ test (push) Successful in 14m43s

This commit is contained in:
Jacob Lifshay 2024-08-06 02:53:45 -07:00
parent cd99dbc849
commit 86fc148806
Signed by: programmerjake
SSH key fingerprint: SHA256:B1iRVvUJkvd7upMIiMqn6OyxvD2SgJkAH3ZnUOj6z+c
2 changed files with 369 additions and 0 deletions

View file

@ -0,0 +1,368 @@
use crate::{
intern::{Intern, Interned},
source_location::SourceLocation,
ty::{DynCanonicalType, Type, Value},
util::DebugAsDisplay,
};
use std::{fmt, hash::Hash};
mod sealed {
pub trait GenericArgsSealed {}
pub trait ToGenericArgSealed {}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct GenericParamName {
pub name: Interned<str>,
pub source_location: SourceLocation,
}
impl GenericParamName {
#[track_caller]
pub fn new(name: &str) -> Self {
Self::new_with_loc(name, SourceLocation::caller())
}
pub fn new_with_loc(name: &str, source_location: SourceLocation) -> Self {
let name = name.intern();
Self {
name,
source_location,
}
}
}
impl fmt::Debug for GenericParamName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.name.fmt(f)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct TypeParam {
pub name: GenericParamName,
pub default: Option<fn(earlier_args: &[GenericArg]) -> TypeArg>,
}
impl fmt::Debug for TypeParam {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TypeParam")
.field("name", &self.name)
.field("default", &self.default.map(|_| DebugAsDisplay("_")))
.finish()
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct ConstParam {
pub name: GenericParamName,
pub default: Option<fn(earlier_args: &[GenericArg]) -> ConstArg>,
}
impl fmt::Debug for ConstParam {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ConstParam")
.field("name", &self.name)
.field("default", &self.default.map(|_| DebugAsDisplay("_")))
.finish()
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum GenericParam {
Type(TypeParam),
Const(ConstParam),
}
impl fmt::Debug for GenericParam {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Type(v) => v.fmt(f),
Self::Const(v) => v.fmt(f),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct TypeArg<T: Type = Interned<dyn DynCanonicalType>> {
pub ty: T,
}
impl<T: Type> TypeArg<T> {
pub fn canonical(&self) -> TypeArg {
TypeArg {
ty: self.ty.canonical_dyn(),
}
}
}
impl<T: Type> sealed::ToGenericArgSealed for T {}
impl<T: Type> ToGenericArg for T {
fn to_generic_arg(this: &Self) -> GenericArg {
GenericArg::Type(TypeArg {
ty: this.canonical_dyn(),
})
}
}
impl<T: Type> sealed::ToGenericArgSealed for TypeArg<T> {}
impl<T: Type> ToGenericArg for TypeArg<T> {
fn to_generic_arg(this: &Self) -> GenericArg {
GenericArg::Type(this.canonical())
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct ConstArg {
pub value: usize,
}
impl sealed::ToGenericArgSealed for usize {}
impl ToGenericArg for usize {
fn to_generic_arg(this: &Self) -> GenericArg {
GenericArg::Const(ConstArg { value: *this })
}
}
impl sealed::ToGenericArgSealed for ConstArg {}
impl ToGenericArg for ConstArg {
fn to_generic_arg(this: &Self) -> GenericArg {
GenericArg::Const(*this)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
pub struct DefaultArg;
impl sealed::ToGenericArgSealed for DefaultArg {}
impl ToGenericArg for DefaultArg {
fn to_generic_arg(this: &Self) -> GenericArg {
GenericArg::Default(*this)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum GenericArg<T: Type = Interned<dyn DynCanonicalType>> {
Type(TypeArg<T>),
Const(ConstArg),
Default(DefaultArg),
}
#[derive(Copy, Clone, Debug)]
pub struct NotATypeArg;
impl fmt::Display for NotATypeArg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("not a type argument")
}
}
impl std::error::Error for NotATypeArg {}
#[derive(Copy, Clone, Debug)]
pub struct NotAConstArg;
impl fmt::Display for NotAConstArg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("not a const argument")
}
}
impl std::error::Error for NotAConstArg {}
impl<T: Type> GenericArg<T> {
pub fn canonical(&self) -> GenericArg {
match self {
GenericArg::Type(v) => GenericArg::Type(v.canonical()),
GenericArg::Const(v) => GenericArg::Const(*v),
GenericArg::Default(v) => GenericArg::Default(*v),
}
}
pub fn ty(self) -> Result<T, NotATypeArg> {
match self {
GenericArg::Type(TypeArg { ty }) => Ok(ty),
GenericArg::Const(_) | GenericArg::Default(_) => Err(NotATypeArg),
}
}
pub fn const_(self) -> Result<usize, NotAConstArg> {
match self {
GenericArg::Const(ConstArg { value }) => Ok(value),
GenericArg::Type(_) | GenericArg::Default(_) => Err(NotAConstArg),
}
}
}
impl<T: Type> fmt::Debug for GenericArg<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Type(v) => v.fmt(f),
Self::Const(v) => v.fmt(f),
Self::Default(v) => v.fmt(f),
}
}
}
impl<T: Type> sealed::ToGenericArgSealed for GenericArg<T> {}
impl<T: Type> ToGenericArg for GenericArg<T> {
fn to_generic_arg(this: &Self) -> GenericArg {
this.canonical()
}
}
pub trait ToGenericArg: sealed::ToGenericArgSealed {
fn to_generic_arg(this: &Self) -> GenericArg;
}
pub trait GenericArgs: sealed::GenericArgsSealed {
fn generic_args(this: &Self) -> Vec<GenericArg>;
}
impl<T: GenericArgs + ?Sized + Send + Sync + 'static> sealed::GenericArgsSealed for Interned<T> {}
impl<T: GenericArgs + ?Sized + Send + Sync + 'static> GenericArgs for Interned<T> {
fn generic_args(this: &Self) -> Vec<GenericArg> {
T::generic_args(this)
}
}
impl<T: GenericArgs + ?Sized> sealed::GenericArgsSealed for Box<T> {}
impl<T: GenericArgs + ?Sized> GenericArgs for Box<T> {
fn generic_args(this: &Self) -> Vec<GenericArg> {
T::generic_args(this)
}
}
impl<T: GenericArgs + ?Sized> sealed::GenericArgsSealed for &'_ T {}
impl<T: GenericArgs + ?Sized> GenericArgs for &'_ T {
fn generic_args(this: &Self) -> Vec<GenericArg> {
T::generic_args(this)
}
}
impl<T: GenericArgs + ?Sized> sealed::GenericArgsSealed for &'_ mut T {}
impl<T: GenericArgs + ?Sized> GenericArgs for &'_ mut T {
fn generic_args(this: &Self) -> Vec<GenericArg> {
T::generic_args(this)
}
}
impl<T: ToGenericArg> sealed::GenericArgsSealed for [T] {}
impl<T: ToGenericArg> GenericArgs for [T] {
fn generic_args(this: &Self) -> Vec<GenericArg> {
Vec::from_iter(this.iter().map(ToGenericArg::to_generic_arg))
}
}
impl<T: ToGenericArg> sealed::GenericArgsSealed for Vec<T> {}
impl<T: ToGenericArg> GenericArgs for Vec<T> {
fn generic_args(this: &Self) -> Vec<GenericArg> {
Vec::from_iter(this.iter().map(ToGenericArg::to_generic_arg))
}
}
impl<T: ToGenericArg, const N: usize> sealed::GenericArgsSealed for [T; N] {}
impl<T: ToGenericArg, const N: usize> GenericArgs for [T; N] {
fn generic_args(this: &Self) -> Vec<GenericArg> {
Vec::from_iter(this.iter().map(ToGenericArg::to_generic_arg))
}
}
macro_rules! impl_generic_args_for_tuples {
($($v:ident: $T:ident),*) => {
impl<$($T: ToGenericArg,)*> sealed::GenericArgsSealed for ($($T,)*) {}
impl<$($T: ToGenericArg,)*> GenericArgs for ($($T,)*) {
fn generic_args(this: &Self) -> Vec<GenericArg> {
let ($($v,)*) = this;
vec![$($T::to_generic_arg($v),)*]
}
}
};
}
impl_generic_args_for_tuples!();
impl_generic_args_for_tuples!(a: A);
impl_generic_args_for_tuples!(a: A, b: B);
impl_generic_args_for_tuples!(a: A, b: B, c: C);
impl_generic_args_for_tuples!(a: A, b: B, c: C, d: D);
impl_generic_args_for_tuples!(a: A, b: B, c: C, d: D, e: E);
impl_generic_args_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F);
impl_generic_args_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
impl_generic_args_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
impl_generic_args_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
impl_generic_args_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
impl_generic_args_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
impl_generic_args_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);
#[track_caller]
pub fn canonical_generic_args(
mut generic_args: Vec<GenericArg>,
generic_params: &[GenericParam],
) -> Interned<[GenericArg]> {
assert!(generic_params.len() >= generic_args.len());
for (i, generic_param) in generic_params.iter().enumerate() {
match generic_args.get(i) {
Some(GenericArg::Default(DefaultArg)) | None => {}
Some(GenericArg::Type(_)) | Some(GenericArg::Const(_)) => continue,
}
let generic_arg = match generic_param {
GenericParam::Type(TypeParam {
name: _,
default: Some(default),
}) => GenericArg::Type(default(&generic_args[..i])),
GenericParam::Type(TypeParam {
name:
GenericParamName {
name,
source_location,
},
default: None,
}) => panic!("Missing type argument for {name} declared here: {source_location}"),
GenericParam::Const(ConstParam {
name: _,
default: Some(default),
}) => GenericArg::Const(default(&generic_args[..i])),
GenericParam::Const(ConstParam {
name:
GenericParamName {
name,
source_location,
},
default: None,
}) => panic!("Missing const argument for {name} declared here: {source_location}"),
};
if i == generic_args.len() {
generic_args.push(generic_arg)
} else {
generic_args[i] = generic_arg;
}
}
debug_assert_eq!(generic_params.len(), generic_args.len());
Intern::intern_owned(generic_args)
}
pub trait GenericType {
type GenericArgs: GenericArgs;
type Type: Type<Value = Self::Value>;
type Value: Value<Type = Self::Type>;
fn generic_params() -> Interned<[GenericParam]>;
#[track_caller]
fn canonical_generic_args(generic_args: &Self::GenericArgs) -> Interned<[GenericArg]> {
canonical_generic_args(
GenericArgs::generic_args(&generic_args),
&Self::generic_params(),
)
}
fn ty(generic_args: Interned<[GenericArg]>) -> Self::Type;
}

View file

@ -32,6 +32,7 @@ pub mod clock;
pub mod enum_;
pub mod expr;
pub mod firrtl;
pub mod generics;
pub mod int;
pub mod intern;
pub mod memory;