WIP adding runtime-evaluated generic parameters
All checks were successful
/ test (push) Successful in 14m43s
All checks were successful
/ test (push) Successful in 14m43s
This commit is contained in:
parent
cd99dbc849
commit
86fc148806
368
crates/fayalite/src/generics.rs
Normal file
368
crates/fayalite/src/generics.rs
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue