From 2c15472e11fa0620ee4a271f79a1be50184d7176 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 7 Aug 2024 03:16:29 -0700 Subject: [PATCH] WIP: use HdlOption[the_type_var] or UInt[123 + n] for creating types --- .forgejo/workflows/test.yml | 21 +- crates/fayalite/src/array.rs | 679 ++------------- crates/fayalite/src/enum_.rs | 645 ++------------ crates/fayalite/src/int.rs | 1554 ++-------------------------------- crates/fayalite/src/lib.rs | 25 +- crates/fayalite/src/ty.rs | 1026 +--------------------- 6 files changed, 243 insertions(+), 3707 deletions(-) diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml index 71f4a3b..b6b7f21 100644 --- a/.forgejo/workflows/test.yml +++ b/.forgejo/workflows/test.yml @@ -7,13 +7,14 @@ jobs: - uses: https://code.forgejo.org/actions/checkout@v3 with: fetch-depth: 0 - - run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.79.0 - source "$HOME/.cargo/env" - echo "$PATH" >> "$GITHUB_PATH" - - uses: https://github.com/Swatinem/rust-cache@v2 - with: - save-if: ${{ github.ref == 'refs/heads/master' }} - - run: cargo test - - run: cargo test --features=unstable-doc - - run: cargo doc --features=unstable-doc +# FIXME: uncomment once the code works again +# - run: | +# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.79.0 +# source "$HOME/.cargo/env" +# echo "$PATH" >> "$GITHUB_PATH" +# - uses: https://github.com/Swatinem/rust-cache@v2 +# with: +# save-if: ${{ github.ref == 'refs/heads/master' }} +# - run: cargo test +# - run: cargo test --features=unstable-doc +# - run: cargo doc --features=unstable-doc diff --git a/crates/fayalite/src/array.rs b/crates/fayalite/src/array.rs index 3763cae..e60c6f9 100644 --- a/crates/fayalite/src/array.rs +++ b/crates/fayalite/src/array.rs @@ -1,671 +1,90 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information + use crate::{ - bundle::{BundleType, BundleValue}, - expr::{ - ops::{ArrayIndex, ArrayLiteral, ExprIndex}, - Expr, ToExpr, - }, - intern::{Intern, Interned, InternedCompare, Memoize}, - module::{ - transform::visit::{Fold, Folder, Visit, Visitor}, - ModuleBuilder, NormalModule, - }, - source_location::SourceLocation, - ty::{ - CanonicalType, CanonicalTypeKind, CanonicalValue, Connect, DynCanonicalType, - DynCanonicalValue, DynType, DynValueTrait, MatchVariantWithoutScope, StaticType, - StaticValue, Type, TypeEnum, Value, ValueEnum, - }, - util::{ConstBool, GenericConstBool, MakeMutSlice}, -}; -use bitvec::{slice::BitSlice, vec::BitVec}; -use std::{ - any::Any, - borrow::{Borrow, BorrowMut}, - fmt, - hash::Hash, - marker::PhantomData, - ops::IndexMut, - sync::Arc, + int::{KnownSize, UNKNOWN_SIZE}, + intern::{Intern, Interned}, + ty::{CanonicalType, StaticType, Type}, }; +use std::ops::Index; -mod sealed { - pub trait Sealed {} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct Array { + element: T, + len: usize, } -pub trait ValueArrayOrSlice: - sealed::Sealed - + BorrowMut<[::Element]> - + AsRef<[::Element]> - + AsMut<[::Element]> - + Hash - + fmt::Debug - + Eq - + Send - + Sync - + 'static - + IndexMut::Element> - + ToOwned - + InternedCompare -{ - type Element: Value::ElementType>; - type ElementType: Type::Element>; - type LenType: 'static + Copy + Ord + fmt::Debug + Hash + Send + Sync; - type Match: 'static - + Clone - + Eq - + fmt::Debug - + Hash - + Send - + Sync - + BorrowMut<[Expr]>; - type MaskVA: ValueArrayOrSlice< - Element = ::MaskValue, - ElementType = ::MaskType, - LenType = Self::LenType, - MaskVA = Self::MaskVA, - > + ?Sized; - type IsStaticLen: GenericConstBool; - const FIXED_LEN_TYPE: Option; - fn make_match(array: Expr>) -> Self::Match; - fn len_from_len_type(v: Self::LenType) -> usize; - #[allow(clippy::result_unit_err)] - fn try_len_type_from_len(v: usize) -> Result; - fn len_type(&self) -> Self::LenType; - fn len(&self) -> usize; - fn is_empty(&self) -> bool; - fn iter(&self) -> std::slice::Iter { - Borrow::<[_]>::borrow(self).iter() - } - fn clone_to_arc(&self) -> Arc; - fn arc_make_mut(v: &mut Arc) -> &mut Self; - fn arc_to_arc_slice(self: Arc) -> Arc<[Self::Element]>; -} +#[allow(non_upper_case_globals)] +pub const Array: ArrayWithoutGenerics = ArrayWithoutGenerics; -impl sealed::Sealed for [T] {} - -impl ValueArrayOrSlice for [V] -where - V::Type: Type, -{ - type Element = V; - type ElementType = V::Type; - type LenType = usize; - type Match = Box<[Expr]>; - type MaskVA = [::MaskValue]; - type IsStaticLen = ConstBool; - const FIXED_LEN_TYPE: Option = None; - - fn make_match(array: Expr>) -> Self::Match { - (0..array.canonical_type().len()) - .map(|index| ArrayIndex::::new_unchecked(array.canonical(), index).to_expr()) - .collect() - } - - fn len_from_len_type(v: Self::LenType) -> usize { - v - } - - fn try_len_type_from_len(v: usize) -> Result { - Ok(v) - } - - fn len_type(&self) -> Self::LenType { - self.len() - } - - fn len(&self) -> usize { - <[_]>::len(self) - } - - fn is_empty(&self) -> bool { - <[_]>::is_empty(self) - } - - fn clone_to_arc(&self) -> Arc { - Arc::from(self) - } - - fn arc_make_mut(v: &mut Arc) -> &mut Self { - MakeMutSlice::make_mut_slice(v) - } - - fn arc_to_arc_slice(self: Arc) -> Arc<[Self::Element]> { - self - } -} - -impl sealed::Sealed for [T; N] {} - -impl ValueArrayOrSlice for [V; N] -where - V::Type: Type, -{ - type Element = V; - type ElementType = V::Type; - type LenType = (); - type Match = [Expr; N]; - type MaskVA = [::MaskValue; N]; - type IsStaticLen = ConstBool; - const FIXED_LEN_TYPE: Option = Some(()); - - fn make_match(array: Expr>) -> Self::Match { - std::array::from_fn(|index| { - ArrayIndex::::new_unchecked(array.canonical(), index).to_expr() - }) - } - - fn len_from_len_type(_v: Self::LenType) -> usize { - N - } - - fn try_len_type_from_len(v: usize) -> Result { - if v == N { - Ok(()) - } else { - Err(()) - } - } - - fn len_type(&self) -> Self::LenType {} - - fn len(&self) -> usize { - N - } - - fn is_empty(&self) -> bool { - N == 0 - } - - fn clone_to_arc(&self) -> Arc { - Arc::new(self.clone()) - } - - fn arc_make_mut(v: &mut Arc) -> &mut Self { - Arc::make_mut(v) - } - - fn arc_to_arc_slice(self: Arc) -> Arc<[Self::Element]> { - self - } -} - -#[derive(Debug, PartialEq, Eq, Hash)] -pub struct ArrayType { - element: VA::ElementType, - len: VA::LenType, - bit_width: usize, -} - -pub trait ArrayTypeTrait: - Type< - CanonicalType = ArrayType<[DynCanonicalValue]>, - Value = Array<::ValueArrayOrSlice>, - CanonicalValue = Array<[DynCanonicalValue]>, - MaskType = ArrayType< - <::ValueArrayOrSlice as ValueArrayOrSlice>::MaskVA, - >, - > + From::ValueArrayOrSlice>> - + Into::ValueArrayOrSlice>> - + BorrowMut::ValueArrayOrSlice>> - + sealed::Sealed - + Connect -{ - type ValueArrayOrSlice: ValueArrayOrSlice - + ?Sized; - type Element: Value; - type ElementType: Type; -} - -impl sealed::Sealed for ArrayType {} - -impl ArrayTypeTrait for ArrayType { - type ValueArrayOrSlice = VA; - type Element = VA::Element; - type ElementType = VA::ElementType; -} - -impl Clone for ArrayType { - fn clone(&self) -> Self { - Self { - element: self.element.clone(), - len: self.len, - bit_width: self.bit_width, - } - } -} - -impl Copy for ArrayType where VA::ElementType: Copy {} - -impl ArrayType { - pub fn element(&self) -> &VA::ElementType { +impl Array { + pub const fn element(&self) -> &T { &self.element } - pub fn len(&self) -> usize { - VA::len_from_len_type(self.len) - } - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - pub fn bit_width(&self) -> usize { - self.bit_width - } - pub fn into_slice_type(self) -> ArrayType<[VA::Element]> { - ArrayType { - len: self.len(), - element: self.element, - bit_width: self.bit_width, - } - } - #[track_caller] - pub fn new_with_len(element: VA::ElementType, len: usize) -> Self { - Self::new_with_len_type( - element, - VA::try_len_type_from_len(len).expect("length should match"), - ) - } - #[track_caller] - pub fn new_with_len_type(element: VA::ElementType, len: VA::LenType) -> Self { - let Some(bit_width) = VA::len_from_len_type(len).checked_mul(element.bit_width()) else { - panic!("array is too big: bit-width overflowed"); - }; - ArrayType { - element, - len, - bit_width, + pub const fn len(&self) -> usize { + if LEN != UNKNOWN_SIZE { + debug_assert!(self.len == LEN); + LEN + } else { + self.len } } } -impl Fold for ArrayType +impl Array where - VA::ElementType: Fold, + (): KnownSize, { - fn fold(self, state: &mut State) -> Result { - state.fold_array_type(self) - } - fn default_fold(self, state: &mut State) -> Result { - Ok(Self::new_with_len_type(self.element.fold(state)?, self.len)) + pub const fn new_static(element: T) -> Self { + Self { element, len: LEN } } } -impl Visit for ArrayType +impl StaticType for Array where - VA::ElementType: Visit, + (): KnownSize, { - fn visit(&self, state: &mut State) -> Result<(), State::Error> { - state.visit_array_type(self) - } - fn default_visit(&self, state: &mut State) -> Result<(), State::Error> { - self.element.visit(state) - } -} - -impl>, const N: usize> ArrayType<[V; N]> { - pub fn new_array(element: V::Type) -> Self { - ArrayType::new_with_len_type(element, ()) - } -} - -impl StaticType for ArrayType<[V; N]> { fn static_type() -> Self { - Self::new_array(StaticType::static_type()) + Self::new_static(T::static_type()) } } -impl>> ArrayType<[V]> { - pub fn new_slice(element: V::Type, len: usize) -> Self { - ArrayType::new_with_len_type(element, len) +impl Array { + pub const fn new_dyn(element: T, len: usize) -> Self { + assert!(len != UNKNOWN_SIZE); + Self { element, len } } } -impl Type for ArrayType { - type CanonicalType = ArrayType<[DynCanonicalValue]>; - type Value = Array; - type CanonicalValue = Array<[DynCanonicalValue]>; - type MaskType = ArrayType; - type MaskValue = Array; - type MatchVariant = VA::Match; - type MatchActiveScope = (); - type MatchVariantAndInactiveScope = MatchVariantWithoutScope; - type MatchVariantsIter = std::iter::Once; - - fn match_variants( - this: Expr, - module_builder: &mut ModuleBuilder, - source_location: SourceLocation, - ) -> Self::MatchVariantsIter - where - IO::Type: BundleType, - { - let _ = module_builder; - let _ = source_location; - std::iter::once(MatchVariantWithoutScope(VA::make_match(this))) - } - - fn mask_type(&self) -> Self::MaskType { - #[derive(Clone, Hash, Eq, PartialEq)] - struct ArrayMaskTypeMemoize(PhantomData); - impl Copy for ArrayMaskTypeMemoize {} - impl Memoize for ArrayMaskTypeMemoize { - type Input = ArrayType; - type InputOwned = ArrayType; - type Output = as Type>::MaskType; - - fn inner(self, input: &Self::Input) -> Self::Output { - ArrayType::new_with_len_type(input.element.mask_type(), input.len) - } - } - ArrayMaskTypeMemoize::(PhantomData).get(self) - } - - fn canonical(&self) -> Self::CanonicalType { - ArrayType { - element: self.element.canonical_dyn(), - len: self.len(), - bit_width: self.bit_width, - } - } - - fn source_location(&self) -> SourceLocation { - SourceLocation::builtin() - } - - fn type_enum(&self) -> TypeEnum { - TypeEnum::ArrayType(self.canonical()) - } - - fn from_canonical_type(t: Self::CanonicalType) -> Self { - Self { - element: VA::ElementType::from_dyn_canonical_type(t.element), - len: VA::try_len_type_from_len(t.len).expect("length should match"), - bit_width: t.bit_width, - } - } - - fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> { - Some(::downcast_ref::>( - this, - )?) +impl Type for Array { + fn canonical(&self) -> CanonicalType { + CanonicalType::Array(Intern::intern_sized(Array::new_dyn( + self.element().canonical(), + self.len(), + ))) } } -impl Connect> - for ArrayType -{ -} +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] +pub struct ArrayWithoutGenerics; -impl CanonicalType for ArrayType<[DynCanonicalValue]> { - const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::ArrayType; -} +impl Index for ArrayWithoutGenerics { + type Output = ArrayWithoutLen; -#[derive(Debug, PartialEq, Eq, Hash)] -pub struct Array { - element_ty: VA::ElementType, - value: Arc, -} - -impl Clone for Array { - fn clone(&self) -> Self { - Self { - element_ty: self.element_ty.clone(), - value: self.value.clone(), - } + fn index(&self, element: T) -> &Self::Output { + Interned::<_>::into_inner(Intern::intern_sized(ArrayWithoutLen { element })) } } -impl ToExpr for Array { - type Type = ArrayType; - - fn ty(&self) -> Self::Type { - ArrayType::new_with_len_type(self.element_ty.clone(), self.value.len_type()) - } - - fn to_expr(&self) -> Expr<::Value> { - Expr::from_value(self) - } +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct ArrayWithoutLen { + element: T, } -impl Value for Array { - fn to_canonical(&self) -> ::CanonicalValue { - Array { - element_ty: self.element_ty.canonical_dyn(), - value: AsRef::<[_]>::as_ref(&*self.value) - .iter() - .map(|v| v.to_canonical_dyn()) - .collect(), - } - } - fn to_bits_impl(this: &Self) -> Interned { - #[derive(Hash, Eq, PartialEq)] - struct ArrayToBitsMemoize(PhantomData); - impl Clone for ArrayToBitsMemoize { - fn clone(&self) -> Self { - *self - } - } - impl Copy for ArrayToBitsMemoize {} - impl Memoize for ArrayToBitsMemoize { - type Input = Array; - type InputOwned = Array; - type Output = Interned; +impl Index for ArrayWithoutLen { + type Output = Array; - fn inner(self, input: &Self::Input) -> Self::Output { - let mut bits = BitVec::with_capacity(input.ty().bit_width()); - for element in AsRef::<[_]>::as_ref(&*input.value).iter() { - bits.extend_from_bitslice(&element.to_bits()); - } - Intern::intern_owned(bits) - } - } - ArrayToBitsMemoize::(PhantomData).get(this) - } -} - -impl CanonicalValue for Array<[DynCanonicalValue]> { - fn value_enum_impl(this: &Self) -> ValueEnum { - ValueEnum::Array(this.clone()) - } - fn to_bits_impl(this: &Self) -> Interned { - Value::to_bits_impl(this) - } -} - -impl Array { - pub fn element_ty(&self) -> &VA::ElementType { - &self.element_ty - } - pub fn len(&self) -> usize { - VA::len_from_len_type(self.value.len_type()) - } - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - pub fn value(&self) -> &Arc { - &self.value - } - pub fn set_element(&mut self, index: usize, element: VA::Element) { - assert_eq!(self.element_ty, element.ty()); - VA::arc_make_mut(&mut self.value)[index] = element; - } - pub fn new(element_ty: VA::ElementType, value: Arc) -> Self { - for element in value.iter() { - assert_eq!(element_ty, element.ty()); - } - Self { element_ty, value } - } - pub fn into_slice(self) -> Array<[VA::Element]> { - Array { - element_ty: self.element_ty, - value: self.value.arc_to_arc_slice(), - } - } -} - -impl>> From for Array -where - VA::Element: StaticValue, -{ - fn from(value: T) -> Self { - Self::new(StaticType::static_type(), value.into()) - } -} - -impl, T: StaticType> ToExpr for [E] { - type Type = ArrayType<[T::Value]>; - - fn ty(&self) -> Self::Type { - ArrayType::new_with_len_type(StaticType::static_type(), self.len()) - } - - fn to_expr(&self) -> Expr<::Value> { - let elements = Intern::intern_owned(Vec::from_iter( - self.iter().map(|v| v.to_expr().to_canonical_dyn()), - )); - ArrayLiteral::new_unchecked(elements, self.ty()).to_expr() - } -} - -impl, T: StaticType> ToExpr for Vec { - type Type = ArrayType<[T::Value]>; - - fn ty(&self) -> Self::Type { - <[E]>::ty(self) - } - - fn to_expr(&self) -> Expr<::Value> { - <[E]>::to_expr(self) - } -} - -impl, T: StaticType, const N: usize> ToExpr for [E; N] { - type Type = ArrayType<[T::Value; N]>; - - fn ty(&self) -> Self::Type { - ArrayType::new_with_len_type(StaticType::static_type(), ()) - } - - fn to_expr(&self) -> Expr<::Value> { - let elements = Intern::intern_owned(Vec::from_iter( - self.iter().map(|v| v.to_expr().to_canonical_dyn()), - )); - ArrayLiteral::new_unchecked(elements, self.ty()).to_expr() - } -} - -#[derive(Clone, Debug)] -pub struct ArrayIntoIter { - array: Arc, - indexes: std::ops::Range, -} - -impl Iterator for ArrayIntoIter { - type Item = VA::Element; - - fn next(&mut self) -> Option { - Some(self.array[self.indexes.next()?].clone()) - } - - fn size_hint(&self) -> (usize, Option) { - self.indexes.size_hint() - } -} - -impl std::iter::FusedIterator for ArrayIntoIter {} - -impl ExactSizeIterator for ArrayIntoIter {} - -impl DoubleEndedIterator for ArrayIntoIter { - fn next_back(&mut self) -> Option { - Some(self.array[self.indexes.next_back()?].clone()) - } -} - -impl Array { - pub fn iter(&self) -> std::slice::Iter<'_, VA::Element> { - self.value.iter() - } -} - -impl<'a, VA: ValueArrayOrSlice> IntoIterator for &'a Array { - type Item = &'a VA::Element; - type IntoIter = std::slice::Iter<'a, VA::Element>; - - fn into_iter(self) -> Self::IntoIter { - self.value.iter() - } -} - -impl IntoIterator for Array { - type Item = VA::Element; - type IntoIter = ArrayIntoIter; - - fn into_iter(self) -> Self::IntoIter { - ArrayIntoIter { - indexes: 0..self.len(), - array: self.value, - } - } -} - -#[derive(Clone, Debug)] -pub struct ArrayExprIter { - array: Expr>, - indexes: std::ops::Range, -} - -impl Iterator for ArrayExprIter { - type Item = Expr; - - fn next(&mut self) -> Option { - Some(ExprIndex::expr_index(self.array, self.indexes.next()?)) - } - - fn size_hint(&self) -> (usize, Option) { - self.indexes.size_hint() - } -} - -impl std::iter::FusedIterator for ArrayExprIter {} - -impl ExactSizeIterator for ArrayExprIter {} - -impl DoubleEndedIterator for ArrayExprIter { - fn next_back(&mut self) -> Option { - Some(ExprIndex::expr_index(self.array, self.indexes.next_back()?)) - } -} - -impl IntoIterator for Expr> { - type Item = Expr; - type IntoIter = ArrayExprIter; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl IntoIterator for &'_ Expr> { - type Item = Expr; - type IntoIter = ArrayExprIter; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl Expr> { - pub fn len(self) -> usize { - self.canonical_type().len() - } - pub fn is_empty(self) -> bool { - self.canonical_type().is_empty() - } - pub fn iter(self) -> ArrayExprIter { - ArrayExprIter { - indexes: 0..self.len(), - array: self, - } + fn index(&self, len: usize) -> &Self::Output { + Interned::<_>::into_inner(Intern::intern_sized(Array::new_dyn(self.element, len))) } } diff --git a/crates/fayalite/src/enum_.rs b/crates/fayalite/src/enum_.rs index 6b9c104..e2e0f28 100644 --- a/crates/fayalite/src/enum_.rs +++ b/crates/fayalite/src/enum_.rs @@ -1,620 +1,91 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -#![allow(clippy::type_complexity)] + use crate::{ - bundle::{BundleValue, TypeHintTrait}, - expr::{ops::VariantAccess, Expr, ToExpr}, - int::{UInt, UIntType}, - intern::{Intern, Interned, MemoizeGeneric}, - module::{ - EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, ModuleBuilder, - NormalModule, Scope, - }, - source_location::SourceLocation, - ty::{ - CanonicalType, CanonicalTypeKind, CanonicalValue, Connect, DynCanonicalType, - DynCanonicalValue, DynType, MatchVariantAndInactiveScope, Type, TypeEnum, Value, ValueEnum, - }, -}; -use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView}; -use hashbrown::HashMap; -use std::{ - borrow::Cow, - fmt, - hash::{Hash, Hasher}, - iter::FusedIterator, - marker::PhantomData, + intern::{Intern, Interned}, + ty::{CanonicalType, StaticType, Type}, }; +use hashbrown::HashSet; +use std::ops::Index; -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub struct VariantType { +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct EnumVariant { pub name: Interned, - pub ty: Option, + pub ty: Option, } -pub struct FmtDebugInEnum<'a, T>(&'a VariantType); - -impl fmt::Debug for FmtDebugInEnum<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let VariantType { name, ref ty } = *self.0; - if let Some(ty) = ty { - write!(f, "{name}({ty:?})") - } else { - write!(f, "{name}") - } - } +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct Enum { + variants: Interned<[EnumVariant]>, } -impl fmt::Display for FmtDebugInEnum<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self, f) - } -} - -impl VariantType { - pub fn map_opt_ty) -> Option>(self, f: F) -> VariantType { - let Self { name, ty } = self; - VariantType { name, ty: f(ty) } - } - pub fn map_ty U>(self, f: F) -> VariantType { - let Self { name, ty } = self; - VariantType { - name, - ty: ty.map(f), - } - } - pub fn as_ref_ty(&self) -> VariantType<&T> { - VariantType { - name: self.name, - ty: self.ty.as_ref(), - } - } - pub fn fmt_debug_in_enum(&self) -> FmtDebugInEnum { - FmtDebugInEnum(self) - } -} - -impl VariantType { - pub fn canonical(&self) -> VariantType { - self.as_ref_ty().map_ty(T::canonical) - } - pub fn to_dyn(&self) -> VariantType> { - self.as_ref_ty().map_ty(T::to_dyn) - } - pub fn canonical_dyn(&self) -> VariantType> { - self.as_ref_ty().map_ty(T::canonical_dyn) - } -} - -impl VariantType> { - pub fn from_canonical_type_helper_has_value(self, expected_name: &str) -> T { - assert_eq!(&*self.name, expected_name, "variant name doesn't match"); - let Some(ty) = self.ty else { - panic!("variant {expected_name} has no value but a value is expected"); - }; - T::from_dyn_canonical_type(ty) - } - pub fn from_canonical_type_helper_no_value(self, expected_name: &str) { - assert_eq!(&*self.name, expected_name, "variant name doesn't match"); - assert!( - self.ty.is_none(), - "variant {expected_name} has a value but is expected to have no value" - ); - } -} - -#[derive(Clone, Eq)] -struct DynEnumTypeImpl { - variants: Interned<[VariantType>]>, - name_indexes: HashMap, usize>, - bit_width: usize, - is_storable: bool, - is_castable_from_bits: bool, -} - -impl fmt::Debug for DynEnumTypeImpl { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "DynEnumType ")?; - f.debug_set() - .entries( - self.variants - .iter() - .map(|variant| variant.fmt_debug_in_enum()), - ) - .finish() - } -} - -impl PartialEq for DynEnumTypeImpl { - fn eq(&self, other: &Self) -> bool { - self.variants == other.variants - } -} - -impl Hash for DynEnumTypeImpl { - fn hash(&self, state: &mut H) { - self.variants.hash(state); - } -} - -#[derive(Copy, Clone, Hash, PartialEq, Eq)] -pub struct DynEnumType(Interned); - -impl fmt::Debug for DynEnumType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -fn discriminant_bit_width_impl(variant_count: usize) -> usize { - variant_count - .next_power_of_two() - .checked_ilog2() - .unwrap_or(0) as usize -} - -impl DynEnumType { +impl Enum { #[track_caller] - pub fn new(variants: Interned<[VariantType>]>) -> Self { - assert!(!variants.is_empty(), "zero-variant enums aren't yet supported: https://github.com/chipsalliance/firrtl-spec/issues/208"); - let mut name_indexes = HashMap::with_capacity(variants.len()); - let mut body_bit_width = 0usize; - let mut is_storable = true; - let mut is_castable_from_bits = true; - for (index, &VariantType { name, ty }) in variants.iter().enumerate() { - if let Some(old_index) = name_indexes.insert(name, index) { - panic!("duplicate variant name {name:?}: at both index {old_index} and {index}"); - } - if let Some(ty) = ty { - assert!( - ty.is_passive(), - "variant type must be a passive type: {ty:?}" - ); - body_bit_width = body_bit_width.max(ty.bit_width()); - is_storable &= ty.is_storable(); - is_castable_from_bits &= ty.is_castable_from_bits(); - } + pub fn new(variants: &[EnumVariant]) -> Self { + let variants = variants.intern(); + let mut names = HashSet::new(); + for variant in variants { + assert!( + names.insert(variant.name), + "duplicate variant name: {:?}", + variant.name + ); } - let bit_width = body_bit_width - .checked_add(discriminant_bit_width_impl(variants.len())) - .unwrap_or_else(|| panic!("enum is too big: bit-width overflowed")); - Self( - DynEnumTypeImpl { - variants, - name_indexes, - bit_width, - is_storable, - is_castable_from_bits, - } - .intern_sized(), - ) - } - pub fn discriminant_bit_width(self) -> usize { - discriminant_bit_width_impl(self.variants().len()) - } - pub fn is_passive(self) -> bool { - true - } - pub fn is_storable(self) -> bool { - self.0.is_storable - } - pub fn is_castable_from_bits(self) -> bool { - self.0.is_castable_from_bits - } - pub fn bit_width(self) -> usize { - self.0.bit_width - } - pub fn name_indexes(&self) -> &HashMap, usize> { - &self.0.name_indexes + Self { variants } } } -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct DynEnum { - ty: DynEnumType, - variant_index: usize, - variant_value: Option, -} - -impl DynEnum { - #[track_caller] - pub fn new_by_index( - ty: DynEnumType, - variant_index: usize, - variant_value: Option, - ) -> Self { - let variant = ty.variants()[variant_index]; - assert_eq!( - variant_value.as_ref().map(|v| v.ty()), - variant.ty, - "variant value doesn't match type" - ); - Self { - ty, - variant_index, - variant_value, - } - } - #[track_caller] - pub fn new_by_name( - ty: DynEnumType, - variant_name: Interned, - variant_value: Option, - ) -> Self { - let variant_index = ty.name_indexes()[&variant_name]; - Self::new_by_index(ty, variant_index, variant_value) - } - pub fn variant_index(&self) -> usize { - self.variant_index - } - pub fn variant_value(&self) -> &Option { - &self.variant_value - } - pub fn variant_with_type(&self) -> VariantType> { - self.ty.variants()[self.variant_index] - } - pub fn variant_name(&self) -> Interned { - self.variant_with_type().name - } - pub fn variant_type(&self) -> Option> { - self.variant_with_type().ty - } - pub fn variant_with_value(&self) -> VariantType<&DynCanonicalValue> { - self.variant_with_type() - .map_opt_ty(|_| self.variant_value.as_ref()) +impl Type for Enum { + fn canonical(&self) -> CanonicalType { + CanonicalType::Enum(*self) } } -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct VariantsHint { - pub known_variants: Interned<[VariantType>]>, - pub more_variants: bool, +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct HdlOption { + some_ty: T, } -impl VariantsHint { - pub fn new( - known_variants: impl IntoIterator>>, - more_variants: bool, - ) -> Self { - let known_variants = Intern::intern_owned(Vec::from_iter(known_variants)); - Self { - known_variants, - more_variants, - } +impl HdlOption { + pub const fn new(some_ty: T) -> Self { + Self { some_ty } } - pub fn check_variant( - self, - index: usize, - variant: VariantType<&dyn DynType>, - ) -> Result<(), String> { - let Some(&known_variant) = self.known_variants.get(index) else { - return if self.more_variants { - Ok(()) - } else { - Err(format!( - "too many variants: name={:?} index={index}", - variant.name - )) - }; - }; - let VariantType { - name: known_name, - ty: type_hint, - } = known_variant; - let VariantType { name, ty } = variant; - if name != known_name { - Err(format!( - "wrong variant name {name:?}, expected {known_name:?}" - )) - } else { - match (ty, type_hint) { - (Some(ty), Some(type_hint)) => type_hint.matches(ty), - (None, None) => Ok(()), - (None, Some(_)) => Err(format!( - "expected variant {name:?} to have type, no type provided" - )), - (Some(_), None) => Err(format!( - "expected variant {name:?} to have no type, but a type was provided" - )), - } - } + pub const fn some_ty(&self) -> &T { + &self.some_ty } } -pub trait EnumType: - Type< - CanonicalType = DynEnumType, - CanonicalValue = DynEnum, - MaskType = UIntType<1>, - MaskValue = UInt<1>, - MatchActiveScope = Scope, - MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope, - MatchVariantsIter = EnumMatchVariantsIter, - > + Connect -where - Self::Value: EnumValue + ToExpr, -{ - type Builder; - fn match_activate_scope( - v: Self::MatchVariantAndInactiveScope, - ) -> (Self::MatchVariant, Self::MatchActiveScope); - fn builder() -> Self::Builder; - fn variants(&self) -> Interned<[VariantType>]>; - fn variants_hint() -> VariantsHint; - #[allow(clippy::result_unit_err)] - fn variant_to_bits( - &self, - variant_index: usize, - variant_value: Option<&VariantValue>, - ) -> Result, ()> { - #[derive(Hash, Eq, PartialEq)] - struct VariantToBitsMemoize(PhantomData<(E, V)>); - impl Clone for VariantToBitsMemoize { - fn clone(&self) -> Self { - *self - } - } - impl Copy for VariantToBitsMemoize {} - impl< - E: EnumType>, - V: ToExpr + Eq + Hash + Send + Sync + 'static + Clone, - > MemoizeGeneric for VariantToBitsMemoize - { - type InputRef<'a> = (&'a E, usize, Option<&'a V>); - type InputOwned = (E, usize, Option); - type InputCow<'a> = (Cow<'a, E>, usize, Option>); - type Output = Result, ()>; +#[allow(non_upper_case_globals)] +pub const HdlOption: HdlOptionWithoutGenerics = HdlOptionWithoutGenerics; - fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> { - (&input.0, input.1, input.2.as_ref()) - } - fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool { - a == b - } - fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned { - (input.0.into_owned(), input.1, input.2.map(Cow::into_owned)) - } - fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a> { - (&input.0, input.1, input.2.as_deref()) - } - fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a> { - (Cow::Owned(input.0), input.1, input.2.map(Cow::Owned)) - } - fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_> { - (Cow::Borrowed(input.0), input.1, input.2.map(Cow::Borrowed)) - } - fn inner(self, input: Self::InputRef<'_>) -> Self::Output { - let (ty, variant_index, variant_value) = input; - let ty = ty.canonical(); - let mut bits = BitVec::with_capacity(ty.bit_width()); - bits.extend_from_bitslice( - &variant_index.view_bits::()[..ty.discriminant_bit_width()], - ); - if let Some(variant_value) = variant_value { - bits.extend_from_bitslice(&variant_value.to_expr().to_literal_bits()?); - } - bits.resize(ty.bit_width(), false); - Ok(Intern::intern_owned(bits)) - } - } - VariantToBitsMemoize::(PhantomData).get(( - self, - variant_index, - variant_value, - )) +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] +pub struct HdlOptionWithoutGenerics; + +impl Index for HdlOptionWithoutGenerics { + type Output = HdlOption; + + fn index(&self, some_ty: T) -> &Self::Output { + Interned::<_>::into_inner(Intern::intern_sized(HdlOption::new(some_ty))) } } -pub trait EnumValue: Value -where - ::Type: EnumType, -{ -} - -pub struct EnumMatchVariantAndInactiveScope(EnumMatchVariantAndInactiveScopeImpl) -where - T::Value: EnumValue; - -impl MatchVariantAndInactiveScope for EnumMatchVariantAndInactiveScope -where - T::Value: EnumValue, -{ - type MatchVariant = T::MatchVariant; - type MatchActiveScope = Scope; - - fn match_activate_scope(self) -> (Self::MatchVariant, Self::MatchActiveScope) { - T::match_activate_scope(self) +impl Type for HdlOption { + fn canonical(&self) -> CanonicalType { + CanonicalType::Enum(Enum::new(&[ + EnumVariant { + name: "None".intern(), + ty: None, + }, + EnumVariant { + name: "Some".intern(), + ty: Some(self.some_ty().canonical()), + }, + ])) } } -impl EnumMatchVariantAndInactiveScope -where - T::Value: EnumValue, -{ - pub fn variant_access(&self) -> Interned>> { - self.0.variant_access() - } - pub fn activate( - self, - ) -> ( - Interned>>, - Scope, - ) { - self.0.activate() - } -} - -#[derive(Clone)] -pub struct EnumMatchVariantsIter -where - T::Value: EnumValue, -{ - pub(crate) inner: EnumMatchVariantsIterImpl, - pub(crate) variant_index: std::ops::Range, -} - -impl Iterator for EnumMatchVariantsIter -where - T::Value: EnumValue, -{ - type Item = EnumMatchVariantAndInactiveScope; - - fn next(&mut self) -> Option { - self.variant_index.next().map(|variant_index| { - EnumMatchVariantAndInactiveScope(self.inner.for_variant_index(variant_index)) - }) - } - - fn size_hint(&self) -> (usize, Option) { - self.variant_index.size_hint() - } -} - -impl ExactSizeIterator for EnumMatchVariantsIter -where - T::Value: EnumValue, -{ - fn len(&self) -> usize { - self.variant_index.len() - } -} - -impl FusedIterator for EnumMatchVariantsIter where T::Value: EnumValue {} - -impl DoubleEndedIterator for EnumMatchVariantsIter -where - T::Value: EnumValue, -{ - fn next_back(&mut self) -> Option { - self.variant_index.next_back().map(|variant_index| { - EnumMatchVariantAndInactiveScope(self.inner.for_variant_index(variant_index)) - }) - } -} - -impl Type for DynEnumType { - type CanonicalType = DynEnumType; - type Value = DynEnum; - type CanonicalValue = DynEnum; - type MaskType = UIntType<1>; - type MaskValue = UInt<1>; - type MatchVariant = Option>; - type MatchActiveScope = Scope; - type MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope; - type MatchVariantsIter = EnumMatchVariantsIter; - - fn match_variants( - this: Expr, - module_builder: &mut ModuleBuilder, - source_location: SourceLocation, - ) -> Self::MatchVariantsIter - where - IO::Type: crate::bundle::BundleType, - { - module_builder.enum_match_variants_helper(this, source_location) - } - - fn mask_type(&self) -> Self::MaskType { - UIntType::new() - } - - fn canonical(&self) -> Self::CanonicalType { - *self - } - - fn source_location(&self) -> SourceLocation { - SourceLocation::builtin() - } - - fn type_enum(&self) -> TypeEnum { - TypeEnum::EnumType(*self) - } - - fn from_canonical_type(t: Self::CanonicalType) -> Self { - t - } - - fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> { - Some(this) - } -} - -impl Connect for DynEnumType {} - -pub struct NoBuilder; - -impl EnumType for DynEnumType { - type Builder = NoBuilder; - - fn match_activate_scope( - v: Self::MatchVariantAndInactiveScope, - ) -> (Self::MatchVariant, Self::MatchActiveScope) { - let (expr, scope) = v.0.activate(); - (expr.variant_type().ty.map(|_| expr.to_expr()), scope) - } - - fn builder() -> Self::Builder { - NoBuilder - } - - fn variants(&self) -> Interned<[VariantType>]> { - self.0.variants - } - - fn variants_hint() -> VariantsHint { - VariantsHint { - known_variants: [][..].intern(), - more_variants: true, - } - } -} - -impl CanonicalType for DynEnumType { - const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::EnumType; -} - -impl ToExpr for DynEnum { - type Type = DynEnumType; - - fn ty(&self) -> Self::Type { - self.ty - } - - fn to_expr(&self) -> Expr<::Value> { - Expr::from_value(self) - } -} - -impl Value for DynEnum { - fn to_canonical(&self) -> ::CanonicalValue { - self.clone() - } - fn to_bits_impl(this: &Self) -> Interned { - this.ty - .variant_to_bits(this.variant_index, this.variant_value.as_ref()) - .unwrap() - } -} - -impl EnumValue for DynEnum {} - -impl CanonicalValue for DynEnum { - fn value_enum_impl(this: &Self) -> ValueEnum { - ValueEnum::Enum(this.clone()) - } - fn to_bits_impl(this: &Self) -> Interned { - this.ty - .variant_to_bits(this.variant_index, this.variant_value.as_ref()) - .unwrap() - } -} - -mod impl_option { - #[allow(dead_code)] - #[derive(crate::ty::Value)] - #[hdl(target(std::option::Option), connect_inexact, outline_generated)] - pub enum Option { - None, - Some(T), +impl StaticType for HdlOption { + fn static_type() -> Self { + HdlOption::new(T::static_type()) } } diff --git a/crates/fayalite/src/int.rs b/crates/fayalite/src/int.rs index ce7d96f..bc20b3e 100644 --- a/crates/fayalite/src/int.rs +++ b/crates/fayalite/src/int.rs @@ -1,1492 +1,108 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -use crate::{ - expr::{Expr, ToExpr}, - intern::{Intern, Interned, Memoize}, - source_location::SourceLocation, - ty::{ - impl_match_values_as_self, CanonicalType, CanonicalTypeKind, CanonicalValue, Connect, - DynCanonicalType, StaticType, Type, TypeEnum, Value, ValueEnum, - }, - util::{ConstBool, GenericConstBool}, - valueless::Valueless, -}; -use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView}; -use num_bigint::{BigInt, BigUint, Sign}; -use num_traits::{ToPrimitive, Zero}; -use std::{ - fmt, - hash::Hash, - marker::PhantomData, - ops::{ - Add, BitAnd, BitOr, BitXor, Bound, Mul, Neg, Not, Range, RangeBounds, RangeInclusive, Shl, - Shr, Sub, - }, -}; -#[derive(Clone, Eq, PartialEq, Hash, Default)] -pub struct IntValue { - ty: T, - uint_value: BigUint, -} +use crate::intern::{Intern, Interned}; +use crate::ty::{CanonicalType, StaticType, Type}; +use std::ops::Index; -pub type DynInt = IntValue>; -pub type DynUInt = DynInt>; -pub type DynSInt = DynInt>; - -pub type Int = IntValue>; -pub type UInt = Int, WIDTH>; -pub type SInt = Int, WIDTH>; - -impl< - T: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > ToExpr for IntValue -{ - type Type = T; - - fn ty(&self) -> Self::Type { - self.ty - } - - fn to_expr(&self) -> Expr<::Value> { - Expr::from_value(self) - } -} - -impl< - T: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > fmt::Display for IntValue -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.to_canonical(), f) - } -} - -impl< - T: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > fmt::Debug for IntValue -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let neg; - let (sign, magnitude) = if self.is_negative() { - neg = self.ty.modulo() - &self.uint_value; - ("-", &neg) - } else if T::Signed::VALUE { - ("+", &self.uint_value) - } else { - ("", &self.uint_value) - }; - write!(f, "{sign}0x{magnitude:X}_{:?}", self.ty) - } -} - -impl Int { - pub fn new>(value: I) -> Self { - Self::with_type::(IntType::new(), value.into()) - } -} - -impl DynInt { - pub fn from_bit_slice(v: &BitSlice) -> Self { - let mut small_buf = [0u32; 8]; - let small_buf_view = small_buf.view_bits_mut::(); - let uint_value = if v.len() <= small_buf_view.len() { - small_buf_view[..v.len()].clone_from_bitslice(v); - BigUint::from_slice(&small_buf) - } else { - let mut buf = BitVec::::with_capacity(v.len()); - buf.extend_from_bitslice(v); - BigUint::from_slice(buf.as_raw_slice()) - }; - Self { - ty: DynIntType::new(v.len()), - uint_value, - } - } -} - -impl< - T: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > IntValue -{ - pub fn with_type>(ty: T, value: I) -> Self { - let int_type = ty.canonical(); - let mut value: BigInt = value.into(); - if value.sign() == Sign::Minus - || usize::try_from(value.bits()) - .map(|v| v > int_type.width) - .unwrap_or(true) - { - value &= BigInt::from(int_type.as_same_width_uint().mask()); - } - Self { - ty, - uint_value: value.try_into().unwrap(), - } - } - pub fn into_canonical(self) -> IntValue> { - IntValue { - ty: self.ty.canonical(), - uint_value: self.uint_value, - } - } - pub fn to_canonical(&self) -> IntValue> { - IntValue { - ty: self.ty.canonical(), - uint_value: self.uint_value.clone(), - } - } - pub fn ty(&self) -> T { - self.ty - } - pub fn uint_value(&self) -> BigUint { - self.uint_value.clone() - } - pub fn into_uint_value(self) -> BigUint { - self.uint_value - } - pub fn value(&self) -> BigInt { - if self.is_negative() { - BigInt::from(self.uint_value.clone()) - BigInt::from(self.ty.modulo()) - } else { - self.uint_value.clone().into() - } - } - pub fn into_value(self) -> BigInt { - if self.is_negative() { - BigInt::from(self.uint_value) - BigInt::from(self.ty.modulo()) - } else { - self.uint_value.into() - } - } - pub fn zero() -> Self - where - T: Default, - { - Self::default() - } - pub fn is_zero(&self) -> bool { - self.uint_value.is_zero() - } - pub fn set_zero(&mut self) { - self.uint_value.set_zero(); - } - pub fn signum(&self) -> SInt<2> { - if self.is_negative() { - IntValue::new(-1) - } else if self.is_zero() { - IntValue::new(0) - } else { - IntValue::new(1) - } - } - pub fn is_positive(&self) -> bool { - !self.is_negative() && !self.is_zero() - } - pub fn is_negative(&self) -> bool { - let width = self.ty.width(); - T::Signed::VALUE && width > 0 && self.uint_value.bit((width - 1).try_into().unwrap()) - } - pub fn into_cast< - NewType: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - >( - self, - new_type: NewType, - ) -> IntValue { - if new_type.width() > self.ty.width() && self.is_negative() { - IntValue::with_type(new_type, self.into_value()) - } else { - IntValue::with_type(new_type, self.into_uint_value()) - } - } - pub fn cast_as_type< - NewType: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - >( - &self, - new_type: NewType, - ) -> IntValue { - if new_type.width() > self.ty.width() && self.is_negative() { - IntValue::with_type(new_type, self.value()) - } else { - IntValue::with_type(new_type, self.uint_value()) - } - } - pub fn cast(self) -> Int { - self.cast_as_type(IntType::new()) - } - pub fn as_same_width_uint(self) -> IntValue { - IntValue { - ty: self.ty.as_same_width_uint(), - uint_value: self.uint_value, - } - } - pub fn as_same_width_sint(self) -> IntValue { - IntValue { - ty: self.ty.as_same_width_sint(), - uint_value: self.uint_value, - } - } - pub fn as_same_value_uint(self) -> IntValue { - IntValue { - ty: self.ty.as_same_value_uint(), - uint_value: self.uint_value, - } - } - pub fn as_same_value_sint(self) -> IntValue { - IntValue { - ty: self.ty.as_same_value_sint(), - uint_value: self.uint_value, - } - } - pub fn bit(&self, index: usize) -> bool { - if index >= self.ty.width() { - self.is_negative() - } else { - self.uint_value.bit(index.try_into().unwrap()) - } - } - pub fn set_bit(&mut self, index: usize, value: bool) { - assert!(index < self.ty.width(), "bit index out of range"); - self.uint_value.set_bit(index.try_into().unwrap(), value) - } - pub fn set_slice< - I: RangeBounds, - RhsType: IntTypeTrait< - Signed = ConstBool, - CanonicalType = DynUIntType, - CanonicalValue = DynUInt, - >, - >( - &mut self, - index: I, - value: impl Into>, - ) { - let (ty, shift) = self.ty.slice_and_shift(index); - let value: IntValue = value.into(); - let value = value.into_cast(ty); - let mut mask = ty.mask(); - let mut uint_value = value.uint_value; - mask <<= shift; - uint_value <<= shift; - // can't just use self.uint_value &= !mask since Not isn't implemented...work around with & and subtraction - mask &= &self.uint_value; - self.uint_value -= mask; - self.uint_value |= uint_value; - } - pub fn with_replaced_slice< - I: RangeBounds, - RhsType: IntTypeTrait< - Signed = ConstBool, - CanonicalType = DynUIntType, - CanonicalValue = DynUInt, - >, - >( - mut self, - index: I, - value: impl Into>, - ) -> Self { - self.set_slice(index, value); - self - } - pub fn concat< - HighType: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - >( - &self, - high_part: IntValue, - ) -> IntValue> { - let self_type = self.ty.canonical(); - let ty = self.valueless().concat(high_part.valueless()).ty; - let mut uint_value = high_part.uint_value << self_type.width; - uint_value |= &self.uint_value; - IntValue { ty, uint_value } - } - pub fn repeat(&self, count: usize) -> IntValue> { - let width = self.ty.width(); - let ty = self.valueless().repeat(count).ty; - let mut factor = BigUint::from(0u8); - // reversed so BigUint only reallocates once - for i in (0..count).rev() { - factor.set_bit((i * width).try_into().unwrap(), true); - } - IntValue { - ty, - uint_value: &self.uint_value * factor, - } - } - pub fn slice>(&self, index: I) -> DynUInt { - let (ty, shift) = self.ty.slice_and_shift(index); - // correct since slice_and_shift ensures we're not trying to slice out of range - IntValue::with_type(ty, &self.uint_value >> shift) - } -} - -impl< - Ty: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > Value for IntValue -{ - fn to_canonical(&self) -> ::CanonicalValue { - IntValue { - ty: self.ty.canonical(), - uint_value: self.uint_value.clone(), - } - } - fn to_bits_impl(this: &Self) -> Interned { - #[derive(Hash, Eq, PartialEq)] - struct ToBitsMemoize(PhantomData); - impl Clone for ToBitsMemoize { - fn clone(&self) -> Self { - *self - } - } - impl Copy for ToBitsMemoize {} - impl< - Ty: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > Memoize for ToBitsMemoize> - { - type Input = IntValue; - type InputOwned = IntValue; - type Output = Interned; - - fn inner(self, input: &Self::Input) -> Self::Output { - let u64_digits = input.uint_value.to_u64_digits(); - let width = input.ty.width(); - let mut bits = BitVec::with_capacity(width); - let mut slice = u64_digits.view_bits::(); - if slice.len() > width { - slice = &slice[..width]; - } - bits.extend_from_bitslice(slice); - bits.resize(width, false); - Intern::intern_owned(bits) - } - } - ToBitsMemoize::(PhantomData).get(this) - } -} - -macro_rules! impl_add_sub { - ($Op:ident::$op:ident) => { - impl $Op> for IntValue - where - LhsType: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - RhsType: IntTypeTrait< - Signed = ::Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - { - type Output = IntValue>; - - fn $op(self, rhs: IntValue) -> Self::Output { - let ty = $Op::$op(self.valueless(), rhs.valueless()).ty; - IntValue::with_type(ty, $Op::$op(self.into_value(), rhs.into_value())) - } - } - - impl $Op> for Valueless - where - LhsType: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - RhsType: IntTypeTrait< - Signed = ::Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - { - type Output = Valueless>; - - fn $op(self, rhs: Valueless) -> Self::Output { - let ty = DynIntType::new( - self.ty - .width() - .max(rhs.ty.width()) - .checked_add(1) - .expect("result has too many bits"), - ); - Valueless { ty } - } - } - }; -} - -macro_rules! impl_bitwise { - ($Op:ident::$op:ident) => { - impl< - Signed: GenericConstBool, - LhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - RhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > $Op> for IntValue - { - type Output = IntValue>; - - fn $op(self, rhs: IntValue) -> Self::Output { - let ty = $Op::$op(self.valueless(), rhs.valueless()).ty; - IntValue::with_type(ty, $Op::$op(self.into_value(), rhs.into_value())) - } - } - - impl< - Signed: GenericConstBool, - LhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - RhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > $Op> for Valueless - { - type Output = Valueless>; - - fn $op(self, rhs: Valueless) -> Self::Output { - let ty = DynIntType::new(self.ty.width().max(rhs.ty.width())); - Valueless { ty } - } - } - }; -} - -impl_add_sub!(Add::add); -impl_add_sub!(Sub::sub); - -impl< - Signed: GenericConstBool, - LhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - RhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > Mul> for IntValue -{ - type Output = IntValue>; - fn mul(self, rhs: IntValue) -> Self::Output { - let ty = self.valueless().mul(rhs.valueless()).ty; - IntValue::with_type(ty, Mul::mul(self.into_value(), rhs.into_value())) - } -} - -impl< - Signed: GenericConstBool, - LhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - RhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > Mul> for Valueless -{ - type Output = Valueless>; - fn mul(self, rhs: Valueless) -> Self::Output { - let ty = DynIntType::new( - self.ty - .width() - .checked_add(rhs.ty.width()) - .expect("product has too many bits"), - ); - Valueless { ty } - } -} - -impl_bitwise!(BitAnd::bitand); -impl_bitwise!(BitOr::bitor); -impl_bitwise!(BitXor::bitxor); - -impl< - Signed: GenericConstBool, - LhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - RhsType: IntTypeTrait< - Signed = ConstBool, - CanonicalType = DynUIntType, - CanonicalValue = DynUInt, - >, - > Shl> for IntValue -{ - type Output = IntValue>; - - fn shl(self, rhs: IntValue) -> Self::Output { - let ty = self.valueless().shl(rhs.valueless()).ty; - IntValue::with_type( - ty, - Shl::shl( - self.into_value(), - rhs.into_value() - .to_usize() - .expect("ty was checked, so the shift must be in-range"), - ), - ) - } -} - -impl< - Signed: GenericConstBool, - LhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - RhsType: IntTypeTrait< - Signed = ConstBool, - CanonicalType = DynUIntType, - CanonicalValue = DynUInt, - >, - > Shl> for Valueless -{ - type Output = Valueless>; - - fn shl(self, rhs: Valueless) -> Self::Output { - let ty = DynIntType::new( - rhs.ty - .width() - .try_into() - .ok() - .and_then(|v| 2usize.checked_pow(v)) - .and_then(|v| self.ty.width().checked_add(v - 1)) - .expect("shift amount can be too big"), - ); - Valueless { ty } - } -} - -impl< - Signed: GenericConstBool, - LhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - RhsType: IntTypeTrait< - Signed = ConstBool, - CanonicalType = DynUIntType, - CanonicalValue = DynUInt, - >, - > Shr> for IntValue -{ - type Output = IntValue>; - - fn shr(self, rhs: IntValue) -> Self::Output { - IntValue::with_type( - self.valueless().shr(rhs.valueless()).ty, - Shr::shr( - self.into_value(), - rhs.into_value().to_usize().unwrap_or(usize::MAX), - ), - ) - } -} - -impl< - Signed: GenericConstBool, - LhsType: IntTypeTrait>, - RhsType: IntTypeTrait< - Signed = ConstBool, - CanonicalType = DynUIntType, - CanonicalValue = DynUInt, - >, - > Shr> for Valueless -{ - type Output = Valueless>; - - fn shr(self, _rhs: Valueless) -> Self::Output { - Valueless { - ty: self.ty.canonical(), - } - } -} - -impl< - Signed: GenericConstBool, - LhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > Shl for IntValue -{ - type Output = IntValue>; - - fn shl(self, rhs: usize) -> Self::Output { - let ty = self.valueless().shl(rhs).ty; - IntValue::with_type(ty, Shl::shl(self.into_value(), rhs)) - } -} - -impl< - Signed: GenericConstBool, - LhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > Shl for Valueless -{ - type Output = Valueless>; - - fn shl(self, rhs: usize) -> Self::Output { - let ty = DynIntType::new( - self.ty - .width() - .checked_add(rhs) - .expect("shift amount is too big"), - ); - Valueless { ty } - } -} - -impl< - Signed: GenericConstBool, - LhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > Shr for IntValue -{ - type Output = IntValue>; - - fn shr(self, rhs: usize) -> Self::Output { - IntValue::with_type( - self.valueless().shr(rhs).ty, - Shr::shr(self.into_value(), rhs), - ) - } -} - -impl< - Signed: GenericConstBool, - LhsType: IntTypeTrait< - Signed = Signed, - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > Shr for Valueless -{ - type Output = Valueless>; - - fn shr(self, rhs: usize) -> Self::Output { - let ty = DynIntType::new(self.ty.width().saturating_sub(rhs).max(1)); - Valueless { ty } - } -} - -impl< - T: IntTypeTrait< - Signed = ConstBool, - CanonicalType = DynSIntType, - CanonicalValue = DynSInt, - >, - > Neg for IntValue -{ - type Output = IntValue; - fn neg(self) -> Self::Output { - let ty = self.valueless().neg().ty; - IntValue::with_type(ty, Neg::neg(self.into_value())) - } -} - -impl< - T: IntTypeTrait< - Signed = ConstBool, - CanonicalType = DynSIntType, - CanonicalValue = DynSInt, - >, - > Neg for Valueless -{ - type Output = Valueless; - fn neg(self) -> Self::Output { - let ty = DynIntType::new( - self.ty - .width() - .checked_add(1) - .expect("result has too many bits"), - ); - Valueless { ty } - } -} - -impl< - T: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > Not for IntValue -{ - type Output = IntValue; - fn not(self) -> Self::Output { - IntValue::with_type(self.valueless().not().ty, Not::not(self.into_value())) - } -} - -impl< - T: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - > Not for Valueless -{ - type Output = Valueless; - fn not(self) -> Self::Output { - self - } -} - -macro_rules! impl_int { - ($ty:ident, $SIGNED:literal) => { - impl From<$ty> for Int, { $ty::BITS as usize }> { - fn from(v: $ty) -> Self { - Self::new(v) - } - } - - impl From, { $ty::BITS as usize }>> for $ty { - fn from(v: Int, { $ty::BITS as usize }>) -> Self { - v.value().try_into().unwrap() - } - } - - impl ToExpr for $ty { - type Type = IntType, { $ty::BITS as usize }>; - - fn ty(&self) -> Self::Type { - IntType::new() - } - - fn to_expr(&self) -> Expr<::Value> { - IntValue::from(*self).to_expr() - } - } - }; -} - -impl_int!(u8, false); -impl_int!(u16, false); -impl_int!(u32, false); -impl_int!(u64, false); -impl_int!(u128, false); -impl_int!(i8, true); -impl_int!(i16, true); -impl_int!(i32, true); -impl_int!(i64, true); -impl_int!(i128, true); - -impl< - T: StaticOrDynIntType< - 1, - Signed = ConstBool, - CanonicalType = DynUIntType, - CanonicalValue = DynUInt, - >, - > From for IntValue -{ - fn from(v: bool) -> Self { - IntValue::with_type(T::new(), v) - } -} - -impl ToExpr for bool { - type Type = UIntType<1>; - - fn ty(&self) -> Self::Type { - IntType::new() - } - - fn to_expr(&self) -> Expr<::Value> { - UInt::from(*self).to_expr() - } -} - -pub trait IntCmp { - type Output; - fn cmp_eq(self, rhs: Rhs) -> Self::Output; - fn cmp_ne(self, rhs: Rhs) -> Self::Output; - fn cmp_lt(self, rhs: Rhs) -> Self::Output; - fn cmp_le(self, rhs: Rhs) -> Self::Output; - fn cmp_gt(self, rhs: Rhs) -> Self::Output; - fn cmp_ge(self, rhs: Rhs) -> Self::Output; -} - -macro_rules! forward_prim_int_cmp { - ($prim_ty:ident) => { - impl IntCmp for $prim_ty - where - IntValue<<$prim_ty as ToExpr>::Type>: IntCmp, - { - type Output = ::Type> as IntCmp>::Output; - fn cmp_eq(self, rhs: Rhs) -> Self::Output { - IntValue::<<$prim_ty as ToExpr>::Type>::from(self).cmp_eq(rhs) - } - fn cmp_ne(self, rhs: Rhs) -> Self::Output { - IntValue::<<$prim_ty as ToExpr>::Type>::from(self).cmp_ne(rhs) - } - fn cmp_lt(self, rhs: Rhs) -> Self::Output { - IntValue::<<$prim_ty as ToExpr>::Type>::from(self).cmp_lt(rhs) - } - fn cmp_le(self, rhs: Rhs) -> Self::Output { - IntValue::<<$prim_ty as ToExpr>::Type>::from(self).cmp_le(rhs) - } - fn cmp_gt(self, rhs: Rhs) -> Self::Output { - IntValue::<<$prim_ty as ToExpr>::Type>::from(self).cmp_gt(rhs) - } - fn cmp_ge(self, rhs: Rhs) -> Self::Output { - IntValue::<<$prim_ty as ToExpr>::Type>::from(self).cmp_ge(rhs) - } - } - }; -} - -forward_prim_int_cmp!(bool); -forward_prim_int_cmp!(u8); -forward_prim_int_cmp!(u16); -forward_prim_int_cmp!(u32); -forward_prim_int_cmp!(u64); -forward_prim_int_cmp!(u128); -forward_prim_int_cmp!(i8); -forward_prim_int_cmp!(i16); -forward_prim_int_cmp!(i32); -forward_prim_int_cmp!(i64); -forward_prim_int_cmp!(i128); +pub const UNKNOWN_SIZE: usize = !0; mod sealed { - pub trait Sealed {} + pub trait KnownSizeSealed {} } -pub trait IntTypeTrait: - sealed::Sealed - + Copy - + 'static - + Eq - + Hash - + fmt::Debug - + Type> - + Connect - + Connect::Signed>> +pub trait KnownSize: + Copy + Send + Sync + 'static + sealed::KnownSizeSealed { - type Signed: GenericConstBool; - type SameWidthUInt: IntTypeTrait< - Signed = ConstBool, - SameWidthUInt = Self::SameWidthUInt, - SameWidthSInt = Self::SameWidthSInt, - CanonicalType = DynUIntType, - CanonicalValue = DynUInt, - >; - type SameWidthSInt: IntTypeTrait< - Signed = ConstBool, - SameWidthUInt = Self::SameWidthUInt, - SameWidthSInt = Self::SameWidthSInt, - CanonicalType = DynSIntType, - CanonicalValue = DynSInt, - >; - fn literal(self, value: impl Into) -> Expr> - where - Self: IntTypeTrait< - CanonicalType = DynIntType<::Signed>, - CanonicalValue = DynInt<::Signed>, - >, - { - IntValue::with_type(self, value).to_expr() - } - fn from_width_unchecked(width: usize) -> Self; - fn width(self) -> usize; - fn as_same_width_uint(self) -> Self::SameWidthUInt; - fn as_same_width_sint(self) -> Self::SameWidthSInt; - fn as_same_value_uint(self) -> DynUIntType { - let mut width = self.width(); - if Self::Signed::VALUE { - width = width.saturating_sub(1); +} + +impl sealed::KnownSizeSealed for () {} + +macro_rules! known_widths { + ([] $($bits:literal)+) => { + impl KnownSize<{ + let v = 0; + $(let v = v * 2 + $bits;)* + v + }> for () {} + }; + ([2 $($rest:tt)*] $($bits:literal)+) => { + known_widths!([$($rest)*] $($bits)* 0); + known_widths!([$($rest)*] $($bits)* 1); + }; + ([2 $($rest:tt)*]) => { + known_widths!([$($rest)*] 0); + known_widths!([$($rest)*] 1); + impl KnownSize<{2 $(* $rest)*}> for () {} + }; +} + +known_widths!([2 2 2 2 2 2 2 2 2]); + +macro_rules! impl_int { + ($name:ident, $generic_name:ident) => { + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub struct $name { + width: usize, } - DynIntType { - width, - _phantom: PhantomData, - } - } - fn as_same_value_sint(self) -> DynSIntType { - let mut width = self.width(); - if !Self::Signed::VALUE { - width = width.checked_add(1).expect("result too big"); - } - DynIntType::new(width) - } - fn min_value(self) -> BigInt { - let width = self.width(); - if Self::Signed::VALUE && width > 0 { - BigInt::from(-1i8) << (width - 1) - } else { - BigInt::from(0u8) - } - } - fn max_value(self) -> BigUint { - (BigUint::from(1u8) << self.width().saturating_sub(Self::Signed::VALUE.into())) - 1u8 - } - fn modulo(self) -> BigUint { - BigUint::from(1u8) << self.width() - } - fn slice_index_to_range>(self, index: I) -> Range { - let width = self.width(); - let start = match index.start_bound() { - Bound::Included(start) => *start, - Bound::Excluded(start) => *start + 1, - Bound::Unbounded => 0, - }; - let end = match index.end_bound() { - Bound::Included(end) => *end + 1, - Bound::Excluded(end) => *end, - Bound::Unbounded => width, - }; - assert!(start <= end && end <= width, "slice range out-of-range"); - start..end - } - fn slice_and_shift>(self, index: I) -> (DynUIntType, usize) { - let range = self.slice_index_to_range(index); - let width = range.end - range.start; - (DynUIntType::new(width), range.start) - } - fn slice>(self, index: I) -> DynUIntType { - self.slice_and_shift(index).0 - } -} -pub trait StaticOrDynIntType: IntTypeTrait { - fn new() -> Self; -} + #[allow(non_upper_case_globals)] + pub const $name: $generic_name = $generic_name; -#[derive(Copy, Clone, PartialEq, Eq, Hash, Default)] -pub struct DynIntType { - pub width: usize, - _phantom: PhantomData, -} - -impl fmt::Debug for DynIntType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if Signed::VALUE { - write!(f, "dyn_i{}", self.width) - } else { - write!(f, "dyn_u{}", self.width) - } - } -} - -impl DynIntType { - pub const fn new(width: usize) -> Self { - Self { - width, - _phantom: PhantomData, - } - } -} - -pub type DynUIntType = DynIntType>; -pub type DynSIntType = DynIntType>; - -impl fmt::Display for DynIntType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}({})", - if Signed::VALUE { "SInt" } else { "UInt" }, - self.width - ) - } -} - -impl DynUIntType { - pub fn mask(self) -> BigUint { - self.modulo() - 1u8 - } - /// gets the smallest `UInt` that fits `v` losslessly - pub fn for_value(v: impl Into) -> Self { - let v: BigUint = v.into(); - Self::new(v.bits().try_into().expect("too big")) - } - /// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty - #[track_caller] - pub fn range(r: Range>) -> Self { - let start: BigUint = r.start.into(); - let end: BigUint = r.end.into(); - assert!(!end.is_zero(), "empty range"); - Self::range_inclusive(start..=(end - 1u8)) - } - /// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty - #[track_caller] - pub fn range_inclusive(r: RangeInclusive>) -> Self { - let (start, end) = r.into_inner(); - let start: BigUint = start.into(); - let end: BigUint = end.into(); - assert!(start <= end, "empty range"); - // no need to check `start`` since it's no larger than `end` - // so must not take more bits than `end` - Self::for_value(end) - } -} - -impl DynSIntType { - /// gets the smallest `SInt` that fits `v` losslessly - pub fn for_value(v: impl Into) -> Self { - let v: BigInt = v.into(); - Self::new( - match v.sign() { - Sign::Minus => { - // account for sign bit and for the minimum value of an `SInt` - // being the negative of the maximum value minus one. - v.not().bits().checked_add(1).expect("too big") + impl $name { + pub const fn width(self) -> usize { + if WIDTH != UNKNOWN_SIZE { + debug_assert!(self.width == WIDTH); + WIDTH + } else { + self.width } - Sign::NoSign => 0, - Sign::Plus => v.bits(), } - .try_into() - .expect("too big"), - ) - } - /// gets the smallest `SInt` that fits `r` losslessly, panics if `r` is empty - #[track_caller] - pub fn range(r: Range>) -> Self { - let start: BigInt = r.start.into(); - let end: BigInt = r.end.into(); - Self::range_inclusive(start..=(end - 1)) - } - /// gets the smallest `SInt` that fits `r` losslessly, panics if `r` is empty - #[track_caller] - pub fn range_inclusive(r: RangeInclusive>) -> Self { - let (start, end) = r.into_inner(); - let start: BigInt = start.into(); - let end: BigInt = end.into(); - assert!(start <= end, "empty range"); - Self::new(Self::for_value(start).width.max(Self::for_value(end).width)) - } -} - -impl sealed::Sealed for DynIntType {} - -impl Type for DynIntType { - type CanonicalType = DynIntType; - type Value = IntValue>; - type CanonicalValue = IntValue>; - type MaskType = UIntType<1>; - type MaskValue = UInt<1>; - - impl_match_values_as_self!(); - - fn mask_type(&self) -> Self::MaskType { - UIntType::new() - } - - fn canonical(&self) -> Self::CanonicalType { - *self - } - - fn source_location(&self) -> SourceLocation { - SourceLocation::builtin() - } - - fn type_enum(&self) -> TypeEnum { - if Signed::VALUE { - TypeEnum::SInt(self.as_same_width_sint()) - } else { - TypeEnum::UInt(self.as_same_width_uint()) } - } - fn from_canonical_type(t: Self::CanonicalType) -> Self { - t - } - - fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> { - Some(this) - } -} - -impl Connect for DynIntType {} - -impl Connect> for DynIntType {} - -impl Connect> for IntType {} - -impl Connect> - for IntType -{ -} - -impl CanonicalType for DynIntType { - const CANONICAL_TYPE_KIND: CanonicalTypeKind = if Signed::VALUE { - CanonicalTypeKind::SInt - } else { - CanonicalTypeKind::UInt - }; -} - -impl CanonicalValue for IntValue> { - fn value_enum_impl(this: &Self) -> ValueEnum { - if Signed::VALUE { - ValueEnum::SInt(this.clone().as_same_width_sint()) - } else { - ValueEnum::UInt(this.clone().as_same_width_uint()) - } - } - fn to_bits_impl(this: &Self) -> Interned { - ::to_bits_impl(this) - } -} - -impl IntTypeTrait for DynIntType { - type Signed = Signed; - type SameWidthUInt = DynUIntType; - type SameWidthSInt = DynSIntType; - - fn width(self) -> usize { - self.width - } - - fn as_same_width_uint(self) -> Self::SameWidthUInt { - DynIntType::new(self.width) - } - - fn as_same_width_sint(self) -> Self::SameWidthSInt { - DynIntType::new(self.width) - } - - fn from_width_unchecked(width: usize) -> Self { - DynIntType::new(width) - } -} - -impl StaticOrDynIntType for DynIntType { - fn new() -> Self { - DynIntType::new(WIDTH) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] -pub struct IntType(PhantomData); - -impl fmt::Debug for IntType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if Signed::VALUE { - write!(f, "i{WIDTH}") - } else { - write!(f, "u{WIDTH}") - } - } -} - -impl IntType { - pub const fn new() -> Self { - Self(PhantomData) - } -} - -pub type UIntType = IntType, WIDTH>; -pub type SIntType = IntType, WIDTH>; - -impl sealed::Sealed for IntType {} - -impl Type for IntType { - type CanonicalType = DynIntType; - type Value = IntValue>; - type CanonicalValue = IntValue>; - type MaskType = UIntType<1>; - type MaskValue = UInt<1>; - - impl_match_values_as_self!(); - - fn mask_type(&self) -> Self::MaskType { - UIntType::new() - } - - fn canonical(&self) -> Self::CanonicalType { - DynIntType::new(WIDTH) - } - - fn source_location(&self) -> SourceLocation { - SourceLocation::builtin() - } - - fn type_enum(&self) -> TypeEnum { - self.canonical().type_enum() - } - - fn from_canonical_type(t: Self::CanonicalType) -> Self { - assert_eq!(t.width, WIDTH); - IntType::new() - } -} - -impl StaticType for IntType { - fn static_type() -> Self { - Self::new() - } -} - -impl IntTypeTrait for IntType { - type Signed = Signed; - type SameWidthUInt = UIntType; - type SameWidthSInt = SIntType; - - fn width(self) -> usize { - WIDTH - } - - fn as_same_width_uint(self) -> Self::SameWidthUInt { - IntType::new() - } - - fn as_same_width_sint(self) -> Self::SameWidthSInt { - IntType::new() - } - - fn from_width_unchecked(_width: usize) -> Self { - IntType::new() - } -} - -impl StaticOrDynIntType - for IntType -{ - fn new() -> Self { - IntType::new() - } -} - -impl fmt::Display for IntType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.canonical().fmt(f) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct IntLiteral<'a, Signed: GenericConstBool, const WIDTH: usize> { - magnitude_le_bytes: &'a [u8], - negative: bool, - _phantom: PhantomData, -} - -#[track_caller] -pub const fn make_int_literal( - negative: bool, - magnitude_le_bytes: &[u8], -) -> IntLiteral<'_, ConstBool, WIDTH> { - IntLiteral::new(negative, magnitude_le_bytes) -} - -impl<'a, Signed: GenericConstBool, const WIDTH: usize> IntLiteral<'a, Signed, WIDTH> { - pub const ZERO: IntLiteral<'static, Signed, WIDTH> = IntLiteral { - magnitude_le_bytes: &[], - negative: false, - _phantom: PhantomData, - }; - #[track_caller] - pub const fn new(negative: bool, mut magnitude_le_bytes: &'a [u8]) -> Self { - while let [prefix @ .., 0] = magnitude_le_bytes { - magnitude_le_bytes = prefix; - } - assert!( - magnitude_le_bytes.len() <= Self::WIDTH_IN_BYTES, - "literal magnitude is too large" - ); - if magnitude_le_bytes.is_empty() { - return Self::ZERO; - } - assert!(WIDTH != 0, "zero-bit integer literal must be zero"); - let retval = Self { - magnitude_le_bytes, - negative, - _phantom: PhantomData, - }; - let Some(magnitude_ilog2) = retval.magnitude_ilog2() else { - panic!("literal magnitude is too large"); - }; - if Self::SIGNED { - if negative { - assert!( - magnitude_ilog2 < Self::WIDTH, - "literal magnitude is too large" - ); - if magnitude_ilog2 == Self::WIDTH - 1 { - // must be `1 << (WIDTH - 1)`, so the msb byte is a - // power of two, and all other bytes are zero - let [prefix @ .., last] = magnitude_le_bytes else { - panic!("checked that magnitude_le_bytes is not empty"); - }; - assert!(last.is_power_of_two(), "literal magnitude is too large"); - let mut i = 0; - while i < prefix.len() { - assert!(prefix[i] == 0, "literal magnitude is too large"); - i += 1; - } - } - } else { - assert!( - magnitude_ilog2 < Self::WIDTH - 1, - "literal magnitude is too large" - ); + impl $name { + pub const fn new_dyn(width: usize) -> Self { + assert!(width != UNKNOWN_SIZE); + Self { width } } - } else { - assert!(!negative, "unsigned literal can't be negative"); - assert!( - magnitude_ilog2 < Self::WIDTH, - "literal magnitude is too large" - ); } - retval - } - pub const fn magnitude_ilog2(self) -> Option { - let Some(&last) = self.magnitude_le_bytes.last() else { - return None; // trying to calculate ilog2 of 0 - }; - // last is known to be non-zero, so ilog2 won't panic - let last_ilog2 = last.ilog2() as usize; - let Some(prod) = (u8::BITS as usize).checked_mul(self.magnitude_le_bytes.len() - 1) else { - return None; // product overflows - }; - last_ilog2.checked_add(prod) - } - pub const fn magnitude_le_bytes(self) -> &'a [u8] { - self.magnitude_le_bytes - } - #[track_caller] - pub const fn magnitude_le_bytes_array(self) -> [u8; N] { - assert!(self.magnitude_le_bytes.len() <= N, "literal too big"); - let mut retval = [0u8; N]; - let mut i = 0; - while i < self.magnitude_le_bytes.len() { - retval[i] = self.magnitude_le_bytes[i]; - i += 1; - } - retval - } - pub const fn wrapping_le_bytes_array(self) -> [u8; N] { - let mut retval = [0u8; N]; - let mut i = 0; - let mut carry = self.negative; - while i < N { - let mut byte = if i < self.magnitude_le_bytes.len() { - self.magnitude_le_bytes[i] - } else { - 0 - }; - if self.negative { - (byte, carry) = (carry as u8).overflowing_add(!byte); + + impl $name + where + (): KnownSize, + { + pub const fn new_static() -> Self { + Self { width: WIDTH } + } + } + + impl Type for $name { + fn canonical(&self) -> CanonicalType { + CanonicalType::$name($name::new_dyn(self.width())) + } + } + + impl StaticType for $name + where + (): KnownSize, + { + fn static_type() -> Self { + Self::new_static() + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] + pub struct $generic_name; + + impl Index for $generic_name { + type Output = $name; + + fn index(&self, width: usize) -> &Self::Output { + Interned::<_>::into_inner(Intern::intern_sized($name::new_dyn(width))) } - retval[i] = byte; - i += 1; } - retval - } - pub const fn negative(self) -> bool { - self.negative - } - pub const SIGNED: bool = Signed::VALUE; - pub const WIDTH: usize = { - // check isize::MAX instead of usize::MAX because we need to be able to have arrays that big - assert!( - WIDTH.div_ceil(u8::BITS as usize) < isize::MAX as usize, - "WIDTH too big" - ); - WIDTH }; - pub const WIDTH_IN_BYTES: usize = { - // use Self::WIDTH instead of WIDTH to assert WIDTH isn't too big - Self::WIDTH.div_ceil(u8::BITS as usize) - }; - pub fn to_int_value(self) -> Int { - Int::new(BigInt::from_bytes_le( - if self.negative() { - Sign::Minus - } else { - Sign::Plus - }, - self.magnitude_le_bytes(), - )) - } - pub fn to_int_expr(self) -> Expr> { - self.to_int_value().to_expr() - } } -const _: () = { - // test make_int_literal - #[track_caller] - const fn check( - negative: bool, - magnitude_le_bytes: &[u8], - expected: i64, - ) { - let value = i64::from_le_bytes( - make_int_literal::(negative, magnitude_le_bytes) - .wrapping_le_bytes_array(), - ); - assert!(value == expected); - } - check::(false, &[0], 0); - check::(true, &[0], 0); - check::(false, &[1], 1); - check::(true, &[1], -1); - check::(false, &[0x7F], 0x7F); - check::(false, &[0x3F], 0x3F); - check::(true, &[0x40], -0x40); - check::(false, &[0xFF], 0xFF); - check::(false, &[0x7F], 0x7F); - check::(true, &[0x80], -0x80); - check::(false, &[0xFF, 0x7F], 0x7FFF); - check::(false, &[0xFF, 0x3F], 0x3FFF); - check::(true, &[0, 0x40], -0x4000); - check::(false, &[0xFF, 0xFF], 0xFFFF); - check::(false, &[0xFF, 0x7F], 0x7FFF); - check::(true, &[0, 0x80], -0x8000); - check::(false, &[0xFF; 9], !0); - check::(false, &[0xFF; 9], !0); - check::(true, &[0xFF; 9], 1); -}; +impl_int!(UInt, UIntWithoutGenerics); +impl_int!(SInt, SIntWithoutGenerics); diff --git a/crates/fayalite/src/lib.rs b/crates/fayalite/src/lib.rs index c0a3775..0a062ee 100644 --- a/crates/fayalite/src/lib.rs +++ b/crates/fayalite/src/lib.rs @@ -24,22 +24,23 @@ pub use fayalite_proc_macros::hdl_module; #[cfg(feature = "unstable-doc")] pub mod _docs; -pub mod annotations; +// FIXME: finish +//pub mod annotations; pub mod array; -pub mod bundle; -pub mod cli; -pub mod clock; +//pub mod bundle; +//pub mod cli; +//pub mod clock; pub mod enum_; -pub mod expr; -pub mod firrtl; +//pub mod expr; +//pub mod firrtl; pub mod int; pub mod intern; -pub mod memory; -pub mod module; -pub mod reg; -pub mod reset; +//pub mod memory; +//pub mod module; +//pub mod reg; +//pub mod reset; pub mod source_location; pub mod ty; pub mod util; -pub mod valueless; -pub mod wire; +//pub mod valueless; +//pub mod wire; diff --git a/crates/fayalite/src/ty.rs b/crates/fayalite/src/ty.rs index 1d7b7e9..3df0214 100644 --- a/crates/fayalite/src/ty.rs +++ b/crates/fayalite/src/ty.rs @@ -1,1016 +1,44 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information + use crate::{ - array::{Array, ArrayType}, - bundle::{BundleType, BundleValue, DynBundle, DynBundleType, FieldType}, - clock::{Clock, ClockType}, - enum_::{DynEnum, DynEnumType, EnumType, VariantType}, - expr::{Expr, ToExpr}, - int::{DynIntType, DynSInt, DynSIntType, DynUInt, DynUIntType, IntTypeTrait, IntValue}, - intern::{Intern, Interned, InternedCompare, PtrEqWithTypeId, SupportsPtrEqWithTypeId}, - module::{ - transform::visit::{Fold, Folder, Visit, Visitor}, - ModuleBuilder, NormalModule, - }, - reset::{AsyncReset, AsyncResetType, Reset, ResetType, SyncReset, SyncResetType}, - source_location::SourceLocation, - util::{iter_eq_by, GenericConstBool}, - valueless::Valueless, -}; -use std::{ - any::{Any, TypeId}, - convert::Infallible, - fmt, - hash::{Hash, Hasher}, - iter::FusedIterator, - marker::PhantomData, - ops::Deref, - sync::Arc, + array::Array, + enum_::Enum, + int::{SInt, UInt}, + intern::{Intern, Interned}, }; +use std::{fmt, hash::Hash}; -#[doc(inline)] -pub use fayalite_proc_macros::Value; - -mod sealed { - pub trait Sealed {} +#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] +pub enum CanonicalType { + UInt(UInt), + SInt(SInt), + Array(Interned>), + Enum(Enum), } -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum TypeEnum { - BundleType(DynBundleType), - EnumType(DynEnumType), - ArrayType(ArrayType<[DynCanonicalValue]>), - UInt(DynUIntType), - SInt(DynSIntType), - Clock(ClockType), - AsyncReset(AsyncResetType), - SyncReset(SyncResetType), - Reset(ResetType), +pub trait Type: Copy + Hash + Eq + fmt::Debug + Send + Sync + 'static { + fn canonical(&self) -> CanonicalType; } -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum CanonicalTypeKind { - BundleType, - EnumType, - ArrayType, - UInt, - SInt, - Clock, - AsyncReset, - SyncReset, - Reset, - DynCanonicalType, -} - -impl CanonicalTypeKind { - pub fn expr_ty(self) -> &'static str { - match self { - CanonicalTypeKind::BundleType => "Expr", - CanonicalTypeKind::EnumType => "Expr", - CanonicalTypeKind::ArrayType => "Expr>", - CanonicalTypeKind::UInt => "Expr", - CanonicalTypeKind::SInt => "Expr", - CanonicalTypeKind::Clock => "Expr", - CanonicalTypeKind::AsyncReset => "Expr", - CanonicalTypeKind::SyncReset => "Expr", - CanonicalTypeKind::Reset => "Expr", - CanonicalTypeKind::DynCanonicalType => "Expr", - } - } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug)] -pub enum ValueEnum { - Bundle(DynBundle), - Enum(DynEnum), - Array(Array<[DynCanonicalValue]>), - UInt(DynUInt), - SInt(DynSInt), - Clock(Clock), - AsyncReset(AsyncReset), - SyncReset(SyncReset), - Reset(Reset), -} - -impl TypeEnum { - pub fn is_passive(self) -> bool { - match self { - TypeEnum::BundleType(ty) => DynBundleType::is_passive(ty), - TypeEnum::EnumType(ty) => DynEnumType::is_passive(ty), - TypeEnum::ArrayType(ty) => ty.element().is_passive(), - TypeEnum::UInt(_) => true, - TypeEnum::SInt(_) => true, - TypeEnum::Clock(_) => true, - TypeEnum::AsyncReset(_) => true, - TypeEnum::SyncReset(_) => true, - TypeEnum::Reset(_) => true, - } - } - pub fn is_storable(self) -> bool { - match self { - TypeEnum::BundleType(ty) => DynBundleType::is_storable(ty), - TypeEnum::EnumType(ty) => DynEnumType::is_storable(ty), - TypeEnum::ArrayType(ty) => ty.element().is_storable(), - TypeEnum::UInt(_) => true, - TypeEnum::SInt(_) => true, - TypeEnum::Clock(_) => false, - TypeEnum::AsyncReset(_) => false, - TypeEnum::SyncReset(_) => false, - TypeEnum::Reset(_) => false, - } - } - pub fn is_castable_from_bits(self) -> bool { - match self { - TypeEnum::BundleType(ty) => DynBundleType::is_castable_from_bits(ty), - TypeEnum::EnumType(ty) => DynEnumType::is_castable_from_bits(ty), - TypeEnum::ArrayType(ty) => ty.element().is_castable_from_bits(), - TypeEnum::UInt(_) => true, - TypeEnum::SInt(_) => true, - TypeEnum::Clock(_) => true, - TypeEnum::AsyncReset(_) => true, - TypeEnum::SyncReset(_) => true, - TypeEnum::Reset(_) => false, // Reset is not castable from bits because we don't know if it's async or sync - } - } - pub fn bit_width(self) -> usize { - match self { - TypeEnum::BundleType(ty) => DynBundleType::bit_width(ty), - TypeEnum::EnumType(ty) => DynEnumType::bit_width(ty), - TypeEnum::ArrayType(ty) => ArrayType::bit_width(&ty), - TypeEnum::UInt(ty) => ty.width, - TypeEnum::SInt(ty) => ty.width, - TypeEnum::Clock(ClockType) - | TypeEnum::AsyncReset(AsyncResetType) - | TypeEnum::SyncReset(SyncResetType) - | TypeEnum::Reset(ResetType) => 1, - } - } - pub fn bundle_type(self) -> Option { - if let TypeEnum::BundleType(retval) = self { - Some(retval) - } else { - None - } - } - pub fn enum_type(self) -> Option { - if let TypeEnum::EnumType(retval) = self { - Some(retval) - } else { - None - } - } - pub fn array_type(self) -> Option> { - if let TypeEnum::ArrayType(retval) = self { - Some(retval) - } else { - None - } - } - pub fn uint(self) -> Option { - if let TypeEnum::UInt(retval) = self { - Some(retval) - } else { - None - } - } - pub fn sint(self) -> Option { - if let TypeEnum::SInt(retval) = self { - Some(retval) - } else { - None - } - } - pub fn clock(self) -> Option { - if let TypeEnum::Clock(retval) = self { - Some(retval) - } else { - None - } - } - pub fn async_reset(self) -> Option { - if let TypeEnum::AsyncReset(retval) = self { - Some(retval) - } else { - None - } - } - pub fn sync_reset(self) -> Option { - if let TypeEnum::SyncReset(retval) = self { - Some(retval) - } else { - None - } - } - pub fn reset(self) -> Option { - if let TypeEnum::Reset(retval) = self { - Some(retval) - } else { - None - } - } - pub fn to_dyn(self) -> Interned { - match self { - TypeEnum::BundleType(ty) => ty.to_dyn(), - TypeEnum::EnumType(ty) => ty.to_dyn(), - TypeEnum::ArrayType(ty) => ty.to_dyn(), - TypeEnum::UInt(ty) => ty.to_dyn(), - TypeEnum::SInt(ty) => ty.to_dyn(), - TypeEnum::Clock(ty) => ty.to_dyn(), - TypeEnum::AsyncReset(ty) => ty.to_dyn(), - TypeEnum::SyncReset(ty) => ty.to_dyn(), - TypeEnum::Reset(ty) => ty.to_dyn(), - } - } - pub fn canonical_dyn(self) -> Interned { - match self { - TypeEnum::BundleType(ty) => ty.canonical_dyn(), - TypeEnum::EnumType(ty) => ty.canonical_dyn(), - TypeEnum::ArrayType(ty) => ty.canonical_dyn(), - TypeEnum::UInt(ty) => ty.canonical_dyn(), - TypeEnum::SInt(ty) => ty.canonical_dyn(), - TypeEnum::Clock(ty) => ty.canonical_dyn(), - TypeEnum::AsyncReset(ty) => ty.canonical_dyn(), - TypeEnum::SyncReset(ty) => ty.canonical_dyn(), - TypeEnum::Reset(ty) => ty.canonical_dyn(), - } - } -} - -pub trait DynType: fmt::Debug + Send + Sync + Any + SupportsPtrEqWithTypeId { - fn canonical_dyn(&self) -> Interned; - fn to_dyn(&self) -> Interned; - fn mask_type_dyn(&self) -> Interned; - fn source_location_dyn(&self) -> SourceLocation; - fn type_enum_dyn(&self) -> TypeEnum; - fn is_passive(&self) -> bool; - fn is_storable(&self) -> bool; - fn is_castable_from_bits(&self) -> bool; - fn bit_width(&self) -> usize; - fn as_dyn_type(&self) -> &dyn DynType; - fn as_dyn_canonical_type(&self) -> Option<&dyn DynCanonicalType>; - #[deprecated = "use ::downcast or ::downcast instead, they properly handle Interned and Interned"] - #[doc(hidden)] - fn as_any(&self) -> &dyn Any; - fn type_name_for_display_only(&self) -> &'static str; - fn from_dyn_canonical_type(ty: Interned) -> Self - where - Self: Type, - { - Self::from_canonical_type( - ::downcast::(&*ty) - .expect("type should match"), - ) - } -} - -impl InternedCompare for dyn DynType { - type InternedCompareKey = PtrEqWithTypeId; - fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { - Self::get_ptr_eq_with_type_id(this) - } - fn interned_compare_key_weak(this: &std::sync::Weak) -> Self::InternedCompareKey { - Self::get_ptr_eq_with_type_id(&*this.upgrade().unwrap()) - } -} - -impl DynType for T { - fn canonical_dyn(&self) -> Interned { - T::canonical_dyn_impl(self) - } - - fn to_dyn(&self) -> Interned { - T::to_dyn_impl(self) - } - - fn mask_type_dyn(&self) -> Interned { - T::mask_type(self).to_dyn() - } - - fn source_location_dyn(&self) -> SourceLocation { - self.source_location() - } - - fn type_enum_dyn(&self) -> TypeEnum { - self.type_enum() - } - - fn is_passive(&self) -> bool { - self.type_enum().is_passive() - } - - fn is_storable(&self) -> bool { - self.type_enum().is_storable() - } - - fn is_castable_from_bits(&self) -> bool { - self.type_enum().is_castable_from_bits() - } - - fn bit_width(&self) -> usize { - self.type_enum().bit_width() - } - - fn as_dyn_type(&self) -> &dyn DynType { - self - } - - fn as_any(&self) -> &dyn Any { - self - } - - fn as_dyn_canonical_type(&self) -> Option<&dyn DynCanonicalType> { - T::as_dyn_canonical_type_impl(self) - } - - fn type_name_for_display_only(&self) -> &'static str { - std::any::type_name::() - } -} - -impl Visit for Interned { - fn visit(&self, state: &mut State) -> Result<(), State::Error> { - state.visit_interned_dyn_type(self) - } - fn default_visit(&self, state: &mut State) -> Result<(), State::Error> { - self.type_enum().visit(state) - } -} - -impl Fold for Interned { - fn fold(self, state: &mut State) -> Result::Error> { - state.fold_interned_dyn_type(self) - } - - fn default_fold(self, state: &mut State) -> Result::Error> { - Ok(self.type_enum().fold(state)?.to_dyn()) - } -} - -impl Visit for Interned { - fn visit(&self, state: &mut State) -> Result<(), State::Error> { - state.visit_interned_dyn_canonical_type(self) - } - fn default_visit(&self, state: &mut State) -> Result<(), State::Error> { - self.type_enum().visit(state) - } -} - -impl Fold for Interned { - fn fold(self, state: &mut State) -> Result::Error> { - state.fold_interned_dyn_canonical_type(self) - } - - fn default_fold(self, state: &mut State) -> Result::Error> { - Ok(self.type_enum().fold(state)?.canonical_dyn()) - } -} - -#[derive(Clone)] -enum DowncastFailedReason<'a, T: Type> { - NotACanonicalType { dyn_type: &'a dyn DynType }, - TypeIdMismatch { dyn_type: &'a dyn DynType }, - _Unused(Infallible, PhantomData T>), -} - -#[derive(Clone)] -pub struct DowncastFailed<'a, T: Type>(DowncastFailedReason<'a, T>); - -impl fmt::Debug for DowncastFailed<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - DowncastFailedReason::NotACanonicalType { dyn_type } => f - .debug_struct("DowncastFailed::NotACanonicalType") - .field("dyn_type", &dyn_type) - .field("target_type", &std::any::type_name::()) - .finish(), - #[allow(deprecated)] - DowncastFailedReason::TypeIdMismatch { dyn_type } => f - .debug_struct("DowncastFailed::TypeIdMismatch") - .field("dyn_type", &dyn_type) - .field("dyn_type_name", &dyn_type.type_name_for_display_only()) - .field("dyn_type_id", &dyn_type.as_any().type_id()) - .field("target_type", &std::any::type_name::()) - .field("target_type_id", &TypeId::of::()) - .finish(), - DowncastFailedReason::_Unused(v, _) => match v {}, - } - } -} - -impl dyn DynType { - pub fn downcast(&self) -> Result> { - let mut this = self; - loop { - #[allow(deprecated)] - if let Some(v) = this.as_any().downcast_ref::>() { - this = &**v; - } else if let Some(v) = this - .as_any() - .downcast_ref::>() - { - this = (**v).as_dyn_type(); - } else { - break; - } - } - if TypeId::of::() == TypeId::of::>() { - ::downcast_ref(&this.to_dyn()).cloned() - } else if TypeId::of::() == TypeId::of::>() { - let Some(dyn_canonical_type) = this.as_dyn_canonical_type() else { - return Err(DowncastFailed(DowncastFailedReason::NotACanonicalType { - dyn_type: this, - })); - }; - let retval = dyn_canonical_type.canonical_dyn(); - ::downcast_ref(&retval).cloned() - } else { - #[allow(deprecated)] - this.as_any().downcast_ref().cloned() - } - .ok_or(DowncastFailed(DowncastFailedReason::TypeIdMismatch { - dyn_type: this, - })) - } -} - -impl dyn DynCanonicalType { - pub fn downcast(&self) -> Result> { - self.as_dyn_type().downcast() - } -} - -pub trait Connect {} - -pub trait MatchVariantAndInactiveScope: Sized { - type MatchVariant; - type MatchActiveScope; - fn match_activate_scope(self) -> (Self::MatchVariant, Self::MatchActiveScope); -} - -#[derive(Debug)] -pub struct MatchVariantWithoutScope(pub T); - -impl MatchVariantAndInactiveScope for MatchVariantWithoutScope { - type MatchVariant = T; - type MatchActiveScope = (); - - fn match_activate_scope(self) -> (Self::MatchVariant, Self::MatchActiveScope) { - (self.0, ()) - } -} - -pub trait Type: DynType + Clone + Hash + Eq + Intern + Connect { - type CanonicalType: CanonicalType< - CanonicalType = Self::CanonicalType, - CanonicalValue = Self::CanonicalValue, - Value = Self::CanonicalValue, - >; - type Value: Value; - type CanonicalValue: CanonicalValue; - type MaskType: Type< - Value = Self::MaskValue, - MaskType = Self::MaskType, - MaskValue = Self::MaskValue, - >; - type MaskValue: Value; - type MatchVariant: 'static + Send + Sync; - type MatchActiveScope; - type MatchVariantAndInactiveScope: MatchVariantAndInactiveScope< - MatchVariant = Self::MatchVariant, - MatchActiveScope = Self::MatchActiveScope, - >; - type MatchVariantsIter: Iterator - + ExactSizeIterator - + FusedIterator - + DoubleEndedIterator; - fn match_variants( - this: Expr, - module_builder: &mut ModuleBuilder, - source_location: SourceLocation, - ) -> Self::MatchVariantsIter - where - IO::Type: BundleType; - fn mask_type(&self) -> Self::MaskType; - fn canonical(&self) -> Self::CanonicalType; - fn canonical_dyn_impl(this: &Self) -> Interned { - Interned::cast_unchecked(this.canonical().intern(), |v| -> &dyn DynCanonicalType { - v - }) - } - fn to_dyn_impl(this: &Self) -> Interned { - Interned::cast_unchecked(this.intern(), |v| -> &dyn DynType { v }) - } - fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> { - let _ = this; - None - } - fn source_location(&self) -> SourceLocation; - fn type_enum(&self) -> TypeEnum; - fn from_canonical_type(t: Self::CanonicalType) -> Self; -} - -pub trait TypeWithDeref: Type { - fn expr_deref(this: &Expr) -> &Self::MatchVariant; -} - -macro_rules! impl_match_values_as_self { - () => { - type MatchVariant = crate::expr::Expr; - type MatchActiveScope = (); - type MatchVariantAndInactiveScope = crate::ty::MatchVariantWithoutScope; - type MatchVariantsIter = std::iter::Once; - - fn match_variants( - this: crate::expr::Expr, - module_builder: &mut crate::module::ModuleBuilder, - source_location: crate::source_location::SourceLocation, - ) -> Self::MatchVariantsIter - where - IO::Type: crate::bundle::BundleType, - { - let _ = module_builder; - let _ = source_location; - std::iter::once(crate::ty::MatchVariantWithoutScope(this)) - } - }; -} - -use bitvec::slice::BitSlice; -pub(crate) use impl_match_values_as_self; - -pub trait DynCanonicalType: DynType + sealed::Sealed {} - -impl InternedCompare for dyn DynCanonicalType { - type InternedCompareKey = PtrEqWithTypeId; - fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { - Self::get_ptr_eq_with_type_id(this) - } - fn interned_compare_key_weak(this: &std::sync::Weak) -> Self::InternedCompareKey { - Self::get_ptr_eq_with_type_id(&*this.upgrade().unwrap()) - } -} - -pub trait CanonicalType: - Copy - + DynCanonicalType - + Type::CanonicalValue> - + sealed::Sealed - + Intern - + Connect -{ - const CANONICAL_TYPE_KIND: CanonicalTypeKind; - fn can_connect(&self, other: &Self) -> bool { - macro_rules! unwrap_other { - ($var:ident = $fn:ident()) => { - let Some($var) = other.type_enum().$fn() else { - return false; - }; - }; - } - match self.type_enum() { - TypeEnum::BundleType(this) => { - unwrap_other!(other = bundle_type()); - iter_eq_by( - this.fields().iter().copied(), - other.fields().iter().copied(), - |this, other| -> bool { - let FieldType { name, flipped, ty } = this; - name == other.name && flipped == other.flipped && ty.can_connect(&other.ty) - }, - ) - } - TypeEnum::EnumType(this) => { - unwrap_other!(other = enum_type()); - iter_eq_by( - this.variants().iter().copied(), - other.variants().iter().copied(), - |this, other| -> bool { - let VariantType { name, ty } = this; - name == other.name - && iter_eq_by(ty, other.ty, |ty, other_ty| ty.can_connect(&other_ty)) - }, - ) - } - TypeEnum::ArrayType(this) => { - unwrap_other!(other = array_type()); - this.len() == other.len() && this.element().can_connect(other.element()) - } - TypeEnum::UInt(_this) => { - unwrap_other!(_other = uint()); - true // all uint widths can connect to all other uint widths - } - TypeEnum::SInt(_this) => { - unwrap_other!(_other = sint()); - true // all sint widths can connect to all other sint widths - } - TypeEnum::Clock(this) => { - unwrap_other!(other = clock()); - this == other - } - TypeEnum::AsyncReset(this) => { - unwrap_other!(other = async_reset()); - this == other - } - TypeEnum::SyncReset(this) => { - unwrap_other!(other = sync_reset()); - this == other - } - TypeEnum::Reset(this) => { - unwrap_other!(other = reset()); - this == other - } - } - } -} - -impl DynCanonicalType for T {} - -pub trait StaticType: Type { - // can't put bounds on full trait, so put it here instead - fn static_type() -> Self - where - Self::Value: Value, - Self::MaskType: StaticType; -} - -pub trait DynValueTrait: fmt::Debug + Send + Sync + Any { - fn ty_dyn(&self) -> Interned; - fn to_canonical_dyn(&self) -> DynCanonicalValue; - fn eq_dyn(&self, other: &dyn DynValueTrait) -> bool; - fn hash_dyn(&self, hasher: &mut dyn Hasher); - fn as_any(&self) -> &(dyn Any + Send + Sync); - fn as_dyn_value_trait(&self) -> &dyn DynValueTrait; - fn as_arc_dyn_value_trait(self: Arc) -> Arc; - fn to_bits(&self) -> Interned; -} - -macro_rules! dyn_value { - ($name:ident, trait = $trait:ident) => { - #[derive(Clone)] - pub struct $name(pub Arc); - - impl Hash for $name { - fn hash(&self, state: &mut H) { - self.0.hash_dyn(state); - } - } - - impl Eq for $name {} - - impl fmt::Debug for $name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } - } - - impl Deref for $name { - type Target = dyn $trait; - - fn deref(&self) -> &Self::Target { - &*self.0 - } - } - }; -} - -dyn_value!(DynValue, trait = DynValueTrait); -dyn_value!(DynCanonicalValue, trait = DynCanonicalValueTrait); - -impl PartialEq for DynValue { - fn eq(&self, other: &Self) -> bool { - self.0.eq_dyn(&*other.0) - } -} - -impl ToExpr for DynValue { - type Type = Interned; - - fn ty(&self) -> Self::Type { - self.0.ty_dyn() - } - - fn to_expr(&self) -> Expr { - Expr::from_value(self) - } -} - -impl Value for DynValue { - fn ty_dyn_impl(this: &Self) -> Interned { - this.ty() - } - - fn to_canonical_dyn_impl(this: &Self) -> DynCanonicalValue { - this.to_canonical() - } - - fn to_canonical(&self) -> ::CanonicalValue { - self.0.to_canonical_dyn() - } - - fn to_bits_impl(this: &Self) -> Interned { - this.0.to_bits() - } -} - -impl PartialEq for DynCanonicalValue { - fn eq(&self, other: &Self) -> bool { - self.0.eq_dyn(other.0.as_dyn_value_trait()) - } -} - -impl ToExpr for DynCanonicalValue { - type Type = Interned; - - fn ty(&self) -> Self::Type { - self.0.ty_dyn_canonical() - } - - fn to_expr(&self) -> Expr { - Expr::from_value(self) - } -} - -impl Value for DynCanonicalValue { - fn ty_dyn_impl(this: &Self) -> Interned { - this.0.ty_dyn() - } - - fn to_canonical_dyn_impl(this: &Self) -> DynCanonicalValue { - this.to_canonical() - } - - fn to_canonical(&self) -> ::CanonicalValue { - self.0.to_canonical_dyn() - } - - fn to_bits_impl(this: &Self) -> Interned { - ::to_bits_impl(this) - } -} - -impl sealed::Sealed for DynCanonicalValue {} - -impl CanonicalValue for DynCanonicalValue { - fn ty_dyn_canonical_impl(this: &Self) -> Interned { - this.0.ty_dyn_canonical() - } - - fn value_enum_impl(this: &Self) -> ValueEnum { - this.0.value_enum() - } - - fn to_bits_impl(this: &Self) -> Interned { - this.0.to_bits() - } -} - -impl Fold for DynCanonicalValue { - fn fold(self, state: &mut State) -> Result::Error> { - state.fold_dyn_canonical_value(self) - } - fn default_fold(self, state: &mut State) -> Result::Error> { - Ok(match self.value_enum().fold(state)? { - ValueEnum::Bundle(v) => v.to_canonical_dyn(), - ValueEnum::Enum(v) => v.to_canonical_dyn(), - ValueEnum::Array(v) => v.to_canonical_dyn(), - ValueEnum::UInt(v) => v.to_canonical_dyn(), - ValueEnum::SInt(v) => v.to_canonical_dyn(), - ValueEnum::Clock(v) => v.to_canonical_dyn(), - ValueEnum::AsyncReset(v) => v.to_canonical_dyn(), - ValueEnum::SyncReset(v) => v.to_canonical_dyn(), - ValueEnum::Reset(v) => v.to_canonical_dyn(), - }) - } -} - -impl Visit for DynCanonicalValue { - fn visit(&self, state: &mut State) -> Result<(), ::Error> { - state.visit_dyn_canonical_value(self) - } - fn default_visit(&self, state: &mut State) -> Result<(), ::Error> { - self.value_enum().visit(state) - } -} - -pub type AsMask = <::Type as Type>::MaskValue; - -pub trait Value: DynValueTrait + Clone + Eq + Hash + ToExpr { - fn ty_dyn_impl(this: &Self) -> Interned { - Interned::cast_unchecked(this.ty().intern_sized(), |v: &Self::Type| -> &dyn DynType { - v - }) - } - fn to_canonical(&self) -> ::CanonicalValue; - fn to_canonical_dyn_impl(this: &Self) -> DynCanonicalValue { - DynCanonicalValue(Arc::new(this.to_canonical())) - } - fn valueless(&self) -> Valueless { - Valueless { ty: self.ty() } - } - fn to_bits_impl(this: &Self) -> Interned { - <::CanonicalValue as CanonicalValue>::to_bits_impl(&this.to_canonical()) - } -} - -pub trait StaticValue: Value> {} - -impl>> StaticValue for T {} - -pub trait DynCanonicalValueTrait: DynValueTrait + sealed::Sealed { - fn ty_dyn_canonical(&self) -> Interned; - fn value_enum(&self) -> ValueEnum; -} - -impl DynCanonicalValueTrait for T -where - T::Type: CanonicalType, -{ - fn ty_dyn_canonical(&self) -> Interned { - Self::ty_dyn_canonical_impl(self) - } - fn value_enum(&self) -> ValueEnum { - Self::value_enum_impl(self) - } -} - -pub trait CanonicalValue: DynCanonicalValueTrait + Value + sealed::Sealed -where - Self::Type: CanonicalType, -{ - fn ty_dyn_canonical_impl(this: &Self) -> Interned { - Interned::cast_unchecked( - this.ty().intern_sized(), - |v: &Self::Type| -> &dyn DynCanonicalType { v }, - ) - } - fn value_enum_impl(this: &Self) -> ValueEnum; - fn to_bits_impl(this: &Self) -> Interned; -} - -impl DynValueTrait for T -where - ::Type: Type, -{ - fn ty_dyn(&self) -> Interned { - T::ty_dyn_impl(self) - } - - fn to_canonical_dyn(&self) -> DynCanonicalValue { - T::to_canonical_dyn_impl(self) - } - - fn eq_dyn(&self, other: &dyn DynValueTrait) -> bool { - let other_any = other.as_any(); - if let Some(other) = other_any.downcast_ref::() { - T::eq(self, other) - } else { - false - } - } - - fn hash_dyn(&self, mut hasher: &mut dyn Hasher) { - self.hash(&mut hasher); - } - - fn as_any(&self) -> &(dyn Any + Send + Sync) { - self - } - - fn as_dyn_value_trait(&self) -> &dyn DynValueTrait { - self - } - - fn as_arc_dyn_value_trait(self: Arc) -> Arc { - self - } - - fn to_bits(&self) -> Interned { - T::to_bits_impl(self) - } -} - -impl Type for Interned { - type CanonicalType = Interned; - type Value = DynValue; - type CanonicalValue = DynCanonicalValue; - type MaskType = Interned; - type MaskValue = DynValue; - - impl_match_values_as_self!(); - - fn mask_type(&self) -> Self::MaskType { - (**self).mask_type_dyn() - } - - fn canonical(&self) -> Self::CanonicalType { - (**self).canonical_dyn() - } - - fn source_location(&self) -> SourceLocation { - (**self).source_location_dyn() - } - - fn type_enum(&self) -> TypeEnum { - (**self).type_enum_dyn() - } - - fn from_canonical_type(t: Self::CanonicalType) -> Self { - Interned::cast_unchecked(t, ::as_dyn_type) - } - - fn canonical_dyn_impl(this: &Self) -> Interned { - this.canonical() - } - - fn to_dyn_impl(this: &Self) -> Interned { - *this - } - - fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> { - (**this).as_dyn_canonical_type() - } -} - -impl Connect for Interned {} - -impl Type for Interned { - type CanonicalType = Interned; - type Value = DynCanonicalValue; - type CanonicalValue = DynCanonicalValue; - type MaskType = Interned; - type MaskValue = DynValue; - - impl_match_values_as_self!(); - - fn mask_type(&self) -> Self::MaskType { - (**self).mask_type_dyn() - } - - fn canonical(&self) -> Self::CanonicalType { +impl Type for CanonicalType { + fn canonical(&self) -> CanonicalType { *self } +} - fn source_location(&self) -> SourceLocation { - (**self).source_location_dyn() - } - - fn type_enum(&self) -> TypeEnum { - (**self).type_enum_dyn() - } - - fn from_canonical_type(t: Self::CanonicalType) -> Self { - t - } - - fn canonical_dyn_impl(this: &Self) -> Interned { - *this - } - - fn to_dyn_impl(this: &Self) -> Interned { - Interned::cast_unchecked(*this, ::as_dyn_type) - } - - fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> { - Some(&**this) +impl Type for Interned { + fn canonical(&self) -> CanonicalType { + T::canonical(self) } } -impl Connect for Interned {} - -impl sealed::Sealed for Interned {} - -impl CanonicalType for Interned { - const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::DynCanonicalType; +pub trait StaticType: Type { + fn static_type() -> Self; } -impl sealed::Sealed for ClockType {} - -impl sealed::Sealed for Clock {} - -impl sealed::Sealed for AsyncResetType {} - -impl sealed::Sealed for AsyncReset {} - -impl sealed::Sealed for SyncResetType {} - -impl sealed::Sealed for SyncReset {} - -impl sealed::Sealed for ResetType {} - -impl sealed::Sealed for Reset {} - -impl sealed::Sealed for DynBundleType {} - -impl sealed::Sealed for DynBundle {} - -impl sealed::Sealed for DynIntType {} - -impl sealed::Sealed for IntValue {} - -impl sealed::Sealed for ArrayType<[DynCanonicalValue]> {} - -impl sealed::Sealed for Array<[DynCanonicalValue]> {} - -impl sealed::Sealed for DynEnumType {} - -impl sealed::Sealed for DynEnum {} +impl StaticType for Interned { + fn static_type() -> Self { + Intern::intern_sized(T::static_type()) + } +}