Compare commits
	
		
			1 commit
		
	
	
		
			master
			...
			runtime-ge
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 86fc148806 | 
					 2 changed files with 369 additions and 0 deletions
				
			
		
							
								
								
									
										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…
	
	Add table
		Add a link
		
	
		Reference in a new issue