Compare commits
1 commit
master
...
type-deduc
Author | SHA1 | Date | |
---|---|---|---|
Jacob Lifshay | 47123eb36b |
|
@ -815,6 +815,12 @@ impl ToTokens for ParsedEnum {
|
|||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #static_type_impl_generics ::fayalite::ty::Connect<::fayalite::type_deduction::UndeducedType>
|
||||
for #type_struct_ident #static_type_type_generics
|
||||
#static_type_where_clause
|
||||
{}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #static_type_impl_generics ::fayalite::ty::Type
|
||||
for #type_struct_ident #static_type_type_generics
|
||||
|
|
|
@ -522,6 +522,12 @@ impl ParsedStruct {
|
|||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::ty::Connect<::fayalite::type_deduction::UndeducedType>
|
||||
for #type_struct_ident #type_generics
|
||||
#where_clause
|
||||
{}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::ty::Type for #type_struct_ident #type_generics
|
||||
#where_clause
|
||||
|
|
|
@ -17,6 +17,7 @@ use crate::{
|
|||
DynCanonicalValue, DynType, DynValueTrait, MatchVariantWithoutScope, StaticType,
|
||||
StaticValue, Type, TypeEnum, Value, ValueEnum,
|
||||
},
|
||||
type_deduction::{HitUndeducedType, UndeducedType},
|
||||
util::{ConstBool, GenericConstBool, MakeMutSlice},
|
||||
};
|
||||
use bitvec::{slice::BitSlice, vec::BitVec};
|
||||
|
@ -195,7 +196,7 @@ where
|
|||
pub struct ArrayType<VA: ValueArrayOrSlice + ?Sized> {
|
||||
element: VA::ElementType,
|
||||
len: VA::LenType,
|
||||
bit_width: usize,
|
||||
bit_width: Result<usize, HitUndeducedType>,
|
||||
}
|
||||
|
||||
pub trait ArrayTypeTrait:
|
||||
|
@ -210,7 +211,6 @@ pub trait ArrayTypeTrait:
|
|||
+ Into<ArrayType<<Self as ArrayTypeTrait>::ValueArrayOrSlice>>
|
||||
+ BorrowMut<ArrayType<<Self as ArrayTypeTrait>::ValueArrayOrSlice>>
|
||||
+ sealed::Sealed
|
||||
+ Connect<Self>
|
||||
{
|
||||
type ValueArrayOrSlice: ValueArrayOrSlice<Element = Self::Element, ElementType = Self::ElementType>
|
||||
+ ?Sized;
|
||||
|
@ -220,6 +220,8 @@ pub trait ArrayTypeTrait:
|
|||
|
||||
impl<VA: ValueArrayOrSlice + ?Sized> sealed::Sealed for ArrayType<VA> {}
|
||||
|
||||
impl<VA: ValueArrayOrSlice + ?Sized> Connect<UndeducedType> for ArrayType<VA> {}
|
||||
|
||||
impl<VA: ValueArrayOrSlice + ?Sized> ArrayTypeTrait for ArrayType<VA> {
|
||||
type ValueArrayOrSlice = VA;
|
||||
type Element = VA::Element;
|
||||
|
@ -248,7 +250,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> ArrayType<VA> {
|
|||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
pub fn bit_width(&self) -> usize {
|
||||
pub fn bit_width(&self) -> Result<usize, HitUndeducedType> {
|
||||
self.bit_width
|
||||
}
|
||||
pub fn into_slice_type(self) -> ArrayType<[VA::Element]> {
|
||||
|
@ -266,10 +268,18 @@ impl<VA: ValueArrayOrSlice + ?Sized> ArrayType<VA> {
|
|||
)
|
||||
}
|
||||
#[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 {
|
||||
fn get_bit_width(
|
||||
element: &VA::ElementType,
|
||||
len: VA::LenType,
|
||||
) -> Result<usize, HitUndeducedType> {
|
||||
let Some(bit_width) = VA::len_from_len_type(len).checked_mul(element.bit_width()?) else {
|
||||
panic!("array is too big: bit-width overflowed");
|
||||
};
|
||||
Ok(bit_width)
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn new_with_len_type(element: VA::ElementType, len: VA::LenType) -> Self {
|
||||
let bit_width = Self::get_bit_width(&element, len);
|
||||
ArrayType {
|
||||
element,
|
||||
len,
|
||||
|
@ -437,7 +447,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> Value for Array<VA> {
|
|||
.collect(),
|
||||
}
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
#[derive(Hash, Eq, PartialEq)]
|
||||
struct ArrayToBitsMemoize<VA: ValueArrayOrSlice + ?Sized>(PhantomData<VA>);
|
||||
impl<VA: ValueArrayOrSlice + ?Sized> Clone for ArrayToBitsMemoize<VA> {
|
||||
|
@ -449,14 +459,14 @@ impl<VA: ValueArrayOrSlice + ?Sized> Value for Array<VA> {
|
|||
impl<VA: ValueArrayOrSlice + ?Sized> Memoize for ArrayToBitsMemoize<VA> {
|
||||
type Input = Array<VA>;
|
||||
type InputOwned = Array<VA>;
|
||||
type Output = Interned<BitSlice>;
|
||||
type Output = Result<Interned<BitSlice>, HitUndeducedType>;
|
||||
|
||||
fn inner(self, input: &Self::Input) -> Self::Output {
|
||||
let mut bits = BitVec::with_capacity(input.ty().bit_width());
|
||||
let mut bits = BitVec::with_capacity(input.ty().bit_width().unwrap_or(0));
|
||||
for element in AsRef::<[_]>::as_ref(&*input.value).iter() {
|
||||
bits.extend_from_bitslice(&element.to_bits());
|
||||
bits.extend_from_bitslice(&element.to_bits()?);
|
||||
}
|
||||
Intern::intern_owned(bits)
|
||||
Ok(Intern::intern_owned(bits))
|
||||
}
|
||||
}
|
||||
ArrayToBitsMemoize::<VA>(PhantomData).get(this)
|
||||
|
@ -467,7 +477,7 @@ impl CanonicalValue for Array<[DynCanonicalValue]> {
|
|||
fn value_enum_impl(this: &Self) -> ValueEnum {
|
||||
ValueEnum::Array(this.clone())
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
Value::to_bits_impl(this)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use crate::{
|
|||
DynCanonicalValue, DynType, MatchVariantWithoutScope, StaticType, Type, TypeEnum,
|
||||
TypeWithDeref, Value, ValueEnum,
|
||||
},
|
||||
type_deduction::{HitUndeducedType, UndeducedType},
|
||||
};
|
||||
use bitvec::{slice::BitSlice, vec::BitVec};
|
||||
use hashbrown::HashMap;
|
||||
|
@ -31,7 +32,7 @@ pub struct FieldType<T> {
|
|||
|
||||
pub struct FmtDebugInStruct<'a, T> {
|
||||
field: &'a FieldType<T>,
|
||||
field_offset: usize,
|
||||
field_offset: Option<usize>,
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for FmtDebugInStruct<'_, T> {
|
||||
|
@ -49,7 +50,9 @@ impl<T: fmt::Debug> fmt::Debug for FmtDebugInStruct<'_, T> {
|
|||
write!(f, "#[hdl(flip)] ")?;
|
||||
}
|
||||
if f.alternate() {
|
||||
writeln!(f, "/* offset = {field_offset} */")?;
|
||||
if let Some(field_offset) = field_offset {
|
||||
writeln!(f, "/* offset = {field_offset} */")?;
|
||||
}
|
||||
}
|
||||
write!(f, "{name}: ")?;
|
||||
ty.fmt(f)
|
||||
|
@ -78,7 +81,7 @@ impl<T> FieldType<T> {
|
|||
ty: &self.ty,
|
||||
}
|
||||
}
|
||||
pub fn fmt_debug_in_struct(&self, field_offset: usize) -> FmtDebugInStruct<'_, T> {
|
||||
pub fn fmt_debug_in_struct(&self, field_offset: Option<usize>) -> FmtDebugInStruct<'_, T> {
|
||||
FmtDebugInStruct {
|
||||
field: self,
|
||||
field_offset,
|
||||
|
@ -135,22 +138,19 @@ struct DynBundleTypeImpl {
|
|||
fields: Interned<[FieldType<Interned<dyn DynCanonicalType>>]>,
|
||||
name_indexes: HashMap<Interned<str>, usize>,
|
||||
field_offsets: Interned<[usize]>,
|
||||
is_passive: bool,
|
||||
is_storable: bool,
|
||||
is_castable_from_bits: bool,
|
||||
bit_width: usize,
|
||||
is_passive: Result<bool, HitUndeducedType>,
|
||||
is_storable: Result<bool, HitUndeducedType>,
|
||||
is_castable_from_bits: Result<bool, HitUndeducedType>,
|
||||
bit_width: Result<usize, HitUndeducedType>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DynBundleTypeImpl {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "DynBundleType ")?;
|
||||
f.debug_set()
|
||||
.entries(
|
||||
self.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, field)| field.fmt_debug_in_struct(self.field_offsets[index])),
|
||||
)
|
||||
.entries(self.fields.iter().enumerate().map(|(index, field)| {
|
||||
field.fmt_debug_in_struct(self.field_offsets.get(index).copied())
|
||||
}))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -178,26 +178,39 @@ impl fmt::Debug for DynBundleType {
|
|||
|
||||
impl DynBundleType {
|
||||
pub fn new(fields: Interned<[FieldType<Interned<dyn DynCanonicalType>>]>) -> Self {
|
||||
let is_passive = fields
|
||||
.iter()
|
||||
.all(|field| !field.flipped && field.ty.is_passive());
|
||||
let is_storable = fields
|
||||
.iter()
|
||||
.all(|field| !field.flipped && field.ty.is_storable());
|
||||
let is_castable_from_bits = fields
|
||||
.iter()
|
||||
.all(|field| !field.flipped && field.ty.is_castable_from_bits());
|
||||
fn calc_prop(
|
||||
fields: Interned<[FieldType<Interned<dyn DynCanonicalType>>]>,
|
||||
property: impl Fn(&Interned<dyn DynCanonicalType>) -> Result<bool, HitUndeducedType>,
|
||||
) -> Result<bool, HitUndeducedType> {
|
||||
fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
if field.flipped {
|
||||
Ok(false)
|
||||
} else {
|
||||
property(&field.ty)
|
||||
}
|
||||
})
|
||||
.fold(Ok(true), HitUndeducedType::reduce_and)
|
||||
}
|
||||
let is_passive = calc_prop(fields, DynType::is_passive);
|
||||
let is_storable = calc_prop(fields, DynType::is_storable);
|
||||
let is_castable_from_bits = calc_prop(fields, DynType::is_castable_from_bits);
|
||||
let mut name_indexes = HashMap::with_capacity(fields.len());
|
||||
let mut field_offsets = Vec::with_capacity(fields.len());
|
||||
let mut bit_width = 0usize;
|
||||
let mut bit_width = Ok(0usize);
|
||||
for (index, &FieldType { name, ty, .. }) in fields.iter().enumerate() {
|
||||
if let Some(old_index) = name_indexes.insert(name, index) {
|
||||
panic!("duplicate field name {name:?}: at both index {old_index} and {index}");
|
||||
}
|
||||
field_offsets.push(bit_width);
|
||||
bit_width = bit_width
|
||||
.checked_add(ty.bit_width())
|
||||
.unwrap_or_else(|| panic!("bundle is too big: bit-width overflowed"));
|
||||
if let Ok(bit_width_value) = bit_width {
|
||||
field_offsets.push(bit_width_value);
|
||||
bit_width = ty.bit_width().map(|field_bit_width| {
|
||||
bit_width_value
|
||||
.checked_add(field_bit_width)
|
||||
.unwrap_or_else(|| panic!("bundle is too big: bit-width overflowed"))
|
||||
});
|
||||
}
|
||||
}
|
||||
Self(
|
||||
DynBundleTypeImpl {
|
||||
|
@ -212,16 +225,16 @@ impl DynBundleType {
|
|||
.intern_sized(),
|
||||
)
|
||||
}
|
||||
pub fn is_passive(self) -> bool {
|
||||
pub fn is_passive(self) -> Result<bool, HitUndeducedType> {
|
||||
self.0.is_passive
|
||||
}
|
||||
pub fn is_storable(self) -> bool {
|
||||
pub fn is_storable(self) -> Result<bool, HitUndeducedType> {
|
||||
self.0.is_storable
|
||||
}
|
||||
pub fn is_castable_from_bits(self) -> bool {
|
||||
pub fn is_castable_from_bits(self) -> Result<bool, HitUndeducedType> {
|
||||
self.0.is_castable_from_bits
|
||||
}
|
||||
pub fn bit_width(self) -> usize {
|
||||
pub fn bit_width(self) -> Result<usize, HitUndeducedType> {
|
||||
self.0.bit_width
|
||||
}
|
||||
pub fn name_indexes(&self) -> &HashMap<Interned<str>, usize> {
|
||||
|
@ -370,7 +383,7 @@ impl FieldsHint {
|
|||
}
|
||||
|
||||
pub trait BundleType:
|
||||
Type<CanonicalType = DynBundleType, CanonicalValue = DynBundle> + TypeWithDeref + Connect<Self>
|
||||
Type<CanonicalType = DynBundleType, CanonicalValue = DynBundle> + TypeWithDeref
|
||||
where
|
||||
Self::Value: BundleValue + ToExpr<Type = Self>,
|
||||
{
|
||||
|
@ -384,7 +397,7 @@ pub trait BundleValue: Value
|
|||
where
|
||||
<Self as ToExpr>::Type: BundleType<Value = Self>,
|
||||
{
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
#[derive(Hash, Eq, PartialEq)]
|
||||
struct ToBitsMemoize<T>(PhantomData<T>);
|
||||
impl<T> Clone for ToBitsMemoize<T> {
|
||||
|
@ -396,21 +409,23 @@ where
|
|||
impl<T: BundleValue<Type: BundleType<Value = T>>> Memoize for ToBitsMemoize<T> {
|
||||
type Input = T;
|
||||
type InputOwned = T;
|
||||
type Output = Interned<BitSlice>;
|
||||
type Output = Result<Interned<BitSlice>, HitUndeducedType>;
|
||||
|
||||
fn inner(self, input: &Self::Input) -> Self::Output {
|
||||
let input = input.to_canonical();
|
||||
let mut bits = BitVec::with_capacity(input.ty.bit_width());
|
||||
let mut bits = BitVec::with_capacity(input.ty.bit_width().unwrap_or(0));
|
||||
for field in input.fields.iter() {
|
||||
bits.extend_from_bitslice(&field.to_bits());
|
||||
bits.extend_from_bitslice(&field.to_bits()?);
|
||||
}
|
||||
Intern::intern_owned(bits)
|
||||
Ok(Intern::intern_owned(bits))
|
||||
}
|
||||
}
|
||||
ToBitsMemoize::<Self>(PhantomData).get(this)
|
||||
}
|
||||
}
|
||||
|
||||
impl Connect<UndeducedType> for DynBundleType {}
|
||||
|
||||
pub struct DynBundleMatch;
|
||||
|
||||
impl Type for DynBundleType {
|
||||
|
@ -534,7 +549,7 @@ impl Value for DynBundle {
|
|||
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
|
||||
self.clone()
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
BundleValue::to_bits_impl(this)
|
||||
}
|
||||
}
|
||||
|
@ -545,7 +560,7 @@ impl CanonicalValue for DynBundle {
|
|||
fn value_enum_impl(this: &Self) -> ValueEnum {
|
||||
ValueEnum::Bundle(this.clone())
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
BundleValue::to_bits_impl(this)
|
||||
}
|
||||
}
|
||||
|
@ -645,6 +660,8 @@ macro_rules! impl_tuple {
|
|||
}
|
||||
}
|
||||
|
||||
impl<$($T,)*> Connect<UndeducedType> for ($($T,)*) {}
|
||||
|
||||
impl<$($T, $T2,)*> Connect<($($T2,)*)> for ($($T,)*)
|
||||
where
|
||||
$($T: Connect<$T2>,)*
|
||||
|
@ -778,7 +795,7 @@ macro_rules! impl_tuple {
|
|||
]),
|
||||
)
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
BundleValue::to_bits_impl(this)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::{
|
|||
impl_match_values_as_self, CanonicalType, CanonicalTypeKind, CanonicalValue, Connect,
|
||||
DynCanonicalType, StaticType, Type, TypeEnum, Value, ValueEnum,
|
||||
},
|
||||
type_deduction::{HitUndeducedType, UndeducedType},
|
||||
util::interned_bit,
|
||||
};
|
||||
use bitvec::slice::BitSlice;
|
||||
|
@ -23,6 +24,8 @@ impl ClockType {
|
|||
}
|
||||
}
|
||||
|
||||
impl Connect<UndeducedType> for ClockType {}
|
||||
|
||||
impl Type for ClockType {
|
||||
type Value = Clock;
|
||||
type CanonicalType = ClockType;
|
||||
|
@ -88,8 +91,8 @@ impl Value for Clock {
|
|||
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
|
||||
*self
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
interned_bit(this.0)
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
Ok(interned_bit(this.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,8 +100,8 @@ impl CanonicalValue for Clock {
|
|||
fn value_enum_impl(this: &Self) -> ValueEnum {
|
||||
ValueEnum::Clock(*this)
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
interned_bit(this.0)
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
Ok(interned_bit(this.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#![allow(clippy::type_complexity)]
|
||||
use crate::{
|
||||
bundle::{BundleValue, TypeHintTrait},
|
||||
expr::{ops::VariantAccess, Expr, ToExpr},
|
||||
expr::{ops::VariantAccess, Expr, NotALiteralExpr, ToExpr},
|
||||
int::{UInt, UIntType},
|
||||
intern::{Intern, Interned, MemoizeGeneric},
|
||||
module::{
|
||||
|
@ -15,6 +15,7 @@ use crate::{
|
|||
CanonicalType, CanonicalTypeKind, CanonicalValue, Connect, DynCanonicalType,
|
||||
DynCanonicalValue, DynType, MatchVariantAndInactiveScope, Type, TypeEnum, Value, ValueEnum,
|
||||
},
|
||||
type_deduction::{HitUndeducedType, UndeducedType},
|
||||
};
|
||||
use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView};
|
||||
use hashbrown::HashMap;
|
||||
|
@ -107,9 +108,9 @@ impl VariantType<Interned<dyn DynCanonicalType>> {
|
|||
struct DynEnumTypeImpl {
|
||||
variants: Interned<[VariantType<Interned<dyn DynCanonicalType>>]>,
|
||||
name_indexes: HashMap<Interned<str>, usize>,
|
||||
bit_width: usize,
|
||||
is_storable: bool,
|
||||
is_castable_from_bits: bool,
|
||||
bit_width: Result<usize, HitUndeducedType>,
|
||||
is_storable: Result<bool, HitUndeducedType>,
|
||||
is_castable_from_bits: Result<bool, HitUndeducedType>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DynEnumTypeImpl {
|
||||
|
@ -158,26 +159,28 @@ impl DynEnumType {
|
|||
pub fn new(variants: Interned<[VariantType<Interned<dyn DynCanonicalType>>]>) -> 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;
|
||||
let mut body_bit_width = Ok(0usize);
|
||||
let mut is_storable = Ok(true);
|
||||
let mut is_castable_from_bits = Ok(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(),
|
||||
ty.is_passive().unwrap_or(true),
|
||||
"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();
|
||||
body_bit_width = body_bit_width.and_then(|v| Ok(v.max(ty.bit_width()?)));
|
||||
is_storable = HitUndeducedType::reduce_and(is_storable, ty.is_storable());
|
||||
is_castable_from_bits =
|
||||
HitUndeducedType::reduce_and(is_castable_from_bits, ty.is_castable_from_bits());
|
||||
}
|
||||
}
|
||||
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"));
|
||||
let bit_width = body_bit_width.map(|v| {
|
||||
v.checked_add(discriminant_bit_width_impl(variants.len()))
|
||||
.unwrap_or_else(|| panic!("enum is too big: bit-width overflowed"))
|
||||
});
|
||||
Self(
|
||||
DynEnumTypeImpl {
|
||||
variants,
|
||||
|
@ -192,16 +195,16 @@ impl DynEnumType {
|
|||
pub fn discriminant_bit_width(self) -> usize {
|
||||
discriminant_bit_width_impl(self.variants().len())
|
||||
}
|
||||
pub fn is_passive(self) -> bool {
|
||||
true
|
||||
pub fn is_passive(self) -> Result<bool, HitUndeducedType> {
|
||||
Ok(true)
|
||||
}
|
||||
pub fn is_storable(self) -> bool {
|
||||
pub fn is_storable(self) -> Result<bool, HitUndeducedType> {
|
||||
self.0.is_storable
|
||||
}
|
||||
pub fn is_castable_from_bits(self) -> bool {
|
||||
pub fn is_castable_from_bits(self) -> Result<bool, HitUndeducedType> {
|
||||
self.0.is_castable_from_bits
|
||||
}
|
||||
pub fn bit_width(self) -> usize {
|
||||
pub fn bit_width(self) -> Result<usize, HitUndeducedType> {
|
||||
self.0.bit_width
|
||||
}
|
||||
pub fn name_indexes(&self) -> &HashMap<Interned<str>, usize> {
|
||||
|
@ -323,14 +326,14 @@ impl VariantsHint {
|
|||
|
||||
pub trait EnumType:
|
||||
Type<
|
||||
CanonicalType = DynEnumType,
|
||||
CanonicalValue = DynEnum,
|
||||
MaskType = UIntType<1>,
|
||||
MaskValue = UInt<1>,
|
||||
MatchActiveScope = Scope,
|
||||
MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>,
|
||||
MatchVariantsIter = EnumMatchVariantsIter<Self>,
|
||||
> + Connect<Self>
|
||||
CanonicalType = DynEnumType,
|
||||
CanonicalValue = DynEnum,
|
||||
MaskType = UIntType<1>,
|
||||
MaskValue = UInt<1>,
|
||||
MatchActiveScope = Scope,
|
||||
MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>,
|
||||
MatchVariantsIter = EnumMatchVariantsIter<Self>,
|
||||
>
|
||||
where
|
||||
Self::Value: EnumValue + ToExpr<Type = Self>,
|
||||
{
|
||||
|
@ -346,7 +349,7 @@ where
|
|||
&self,
|
||||
variant_index: usize,
|
||||
variant_value: Option<&VariantValue>,
|
||||
) -> Result<Interned<BitSlice>, ()> {
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
#[derive(Hash, Eq, PartialEq)]
|
||||
struct VariantToBitsMemoize<E, V>(PhantomData<(E, V)>);
|
||||
impl<E, V> Clone for VariantToBitsMemoize<E, V> {
|
||||
|
@ -363,7 +366,7 @@ where
|
|||
type InputRef<'a> = (&'a E, usize, Option<&'a V>);
|
||||
type InputOwned = (E, usize, Option<V>);
|
||||
type InputCow<'a> = (Cow<'a, E>, usize, Option<Cow<'a, V>>);
|
||||
type Output = Result<Interned<BitSlice>, ()>;
|
||||
type Output = Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr>;
|
||||
|
||||
fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> {
|
||||
(&input.0, input.1, input.2.as_ref())
|
||||
|
@ -386,15 +389,22 @@ where
|
|||
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());
|
||||
let bit_width = match ty.bit_width() {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Ok(Err(e)),
|
||||
};
|
||||
let mut bits = BitVec::with_capacity(bit_width);
|
||||
bits.extend_from_bitslice(
|
||||
&variant_index.view_bits::<Lsb0>()[..ty.discriminant_bit_width()],
|
||||
);
|
||||
if let Some(variant_value) = variant_value {
|
||||
bits.extend_from_bitslice(&variant_value.to_expr().to_literal_bits()?);
|
||||
match variant_value.to_expr().to_literal_bits()? {
|
||||
Ok(variant_value) => bits.extend_from_bitslice(&variant_value),
|
||||
Err(e) => return Ok(Err(e)),
|
||||
}
|
||||
}
|
||||
bits.resize(ty.bit_width(), false);
|
||||
Ok(Intern::intern_owned(bits))
|
||||
bits.resize(bit_width, false);
|
||||
Ok(Ok(Intern::intern_owned(bits)))
|
||||
}
|
||||
}
|
||||
VariantToBitsMemoize::<Self, VariantValue>(PhantomData).get((
|
||||
|
@ -492,6 +502,8 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl Connect<UndeducedType> for DynEnumType {}
|
||||
|
||||
impl Type for DynEnumType {
|
||||
type CanonicalType = DynEnumType;
|
||||
type Value = DynEnum;
|
||||
|
@ -589,7 +601,7 @@ impl Value for DynEnum {
|
|||
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
|
||||
self.clone()
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
this.ty
|
||||
.variant_to_bits(this.variant_index, this.variant_value.as_ref())
|
||||
.unwrap()
|
||||
|
@ -602,7 +614,7 @@ impl CanonicalValue for DynEnum {
|
|||
fn value_enum_impl(this: &Self) -> ValueEnum {
|
||||
ValueEnum::Enum(this.clone())
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
this.ty
|
||||
.variant_to_bits(this.variant_index, this.variant_value.as_ref())
|
||||
.unwrap()
|
||||
|
|
|
@ -17,6 +17,7 @@ use crate::{
|
|||
DynCanonicalType, DynCanonicalValue, DynType, DynValue, DynValueTrait, Type, TypeWithDeref,
|
||||
Value,
|
||||
},
|
||||
type_deduction::HitUndeducedType,
|
||||
util::ConstBool,
|
||||
valueless::Valueless,
|
||||
wire::Wire,
|
||||
|
@ -51,8 +52,7 @@ macro_rules! expr_enum {
|
|||
$(Self::$Variant(v) => v.target(),)+
|
||||
}
|
||||
}
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
pub fn to_literal_bits(&self) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
match self {
|
||||
$(Self::$Variant(v) => v.to_literal_bits(),)+
|
||||
}
|
||||
|
@ -176,6 +176,18 @@ pub struct Expr<T> {
|
|||
__phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct NotALiteralExpr;
|
||||
|
||||
impl fmt::Display for NotALiteralExpr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Not a literal expression")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for NotALiteralExpr {}
|
||||
|
||||
impl<T> Expr<T> {
|
||||
pub fn expr_enum(self) -> ExprEnum {
|
||||
self.__enum
|
||||
|
@ -210,8 +222,9 @@ impl<T> Expr<T> {
|
|||
{
|
||||
Valueless { ty: self.ty() }
|
||||
}
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
pub fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.expr_enum().to_literal_bits()
|
||||
}
|
||||
#[track_caller]
|
||||
|
@ -796,8 +809,9 @@ pub trait ExprTrait: ExprTraitBase {
|
|||
fn valueless(&self) -> Valueless<Self::Type> {
|
||||
Valueless { ty: self.ty() }
|
||||
}
|
||||
#[allow(clippy::result_unit_err)]
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()>;
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr>;
|
||||
}
|
||||
|
||||
impl<T: ExprTrait> ExprTraitBase for T {}
|
||||
|
@ -875,7 +889,7 @@ impl<T: Type> Literal<T> {
|
|||
#[track_caller]
|
||||
pub fn new_unchecked(value: T::CanonicalValue) -> Self {
|
||||
assert!(
|
||||
value.ty().is_passive(),
|
||||
value.ty().is_passive().unwrap_or(true),
|
||||
"can't have a literal with flipped fields"
|
||||
);
|
||||
Self { value }
|
||||
|
@ -918,7 +932,9 @@ impl<T: Type> ExprTrait for Literal<T> {
|
|||
None
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
Ok(self.value.to_bits())
|
||||
}
|
||||
}
|
||||
|
@ -974,8 +990,10 @@ impl<T: Type> ExprTrait for ModuleIO<T> {
|
|||
))
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
Err(())
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
Err(NotALiteralExpr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1008,8 +1026,10 @@ where
|
|||
Some(Intern::intern_sized(self.canonical().into()))
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
Err(())
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
Err(NotALiteralExpr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1024,8 +1044,10 @@ impl<T: Type> ExprTrait for Wire<T> {
|
|||
Some(Intern::intern_sized(self.to_dyn_canonical_wire().into()))
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
Err(())
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
Err(NotALiteralExpr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1040,8 +1062,10 @@ impl<T: Type> ExprTrait for Reg<T> {
|
|||
Some(Intern::intern_sized(self.to_dyn_canonical_reg().into()))
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
Err(())
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
Err(NotALiteralExpr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1089,7 +1113,9 @@ where
|
|||
fn target(&self) -> Option<Interned<Target>> {
|
||||
Some(Intern::intern_sized(self.canonical().into()))
|
||||
}
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
Err(())
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
Err(NotALiteralExpr)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ use crate::{
|
|||
clock::{Clock, ClockType, ToClock},
|
||||
enum_::{DynEnumType, EnumType, EnumValue, VariantType},
|
||||
expr::{
|
||||
sealed, Expr, ExprEnum, ExprTrait, Target, TargetPathArrayElement, TargetPathBundleField,
|
||||
TargetPathDynArrayElement, TargetPathElement, ToExpr,
|
||||
sealed, Expr, ExprEnum, ExprTrait, NotALiteralExpr, Target, TargetPathArrayElement,
|
||||
TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, ToExpr,
|
||||
},
|
||||
int::{
|
||||
DynInt, DynIntType, DynSInt, DynSIntType, DynUInt, DynUIntType, StaticOrDynIntType, Int,
|
||||
IntCmp, IntType, IntTypeTrait, IntValue, UInt, UIntType,
|
||||
DynInt, DynIntType, DynSInt, DynSIntType, DynUInt, DynUIntType, Int, IntCmp, IntType,
|
||||
IntTypeTrait, IntValue, StaticOrDynIntType, UInt, UIntType,
|
||||
},
|
||||
intern::{Intern, Interned},
|
||||
reset::{
|
||||
|
@ -19,9 +19,9 @@ use crate::{
|
|||
ToReset, ToSyncReset,
|
||||
},
|
||||
ty::{
|
||||
CanonicalType, CanonicalValue, DynCanonicalType, DynCanonicalValue, DynType, DynValueTrait,
|
||||
Type, Value,
|
||||
CanonicalType, CanonicalValue, DynCanonicalType, DynCanonicalValue, DynType, Type, Value,
|
||||
},
|
||||
type_deduction::HitUndeducedType,
|
||||
util::{interned_bit, ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool},
|
||||
valueless::{Valueless, ValuelessTr},
|
||||
};
|
||||
|
@ -33,6 +33,43 @@ use std::{
|
|||
ops::{self, Index, Range, RangeBounds},
|
||||
};
|
||||
|
||||
fn unary_literal_bits<V: Value<Type: Type<Value = V>>>(
|
||||
v: Expr<V>,
|
||||
f: impl FnOnce(Interned<BitSlice>) -> Interned<BitSlice>,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
Ok(v.to_literal_bits()?.map(f))
|
||||
}
|
||||
|
||||
fn try_unary_literal_bits<V: Value<Type: Type<Value = V>>>(
|
||||
v: Expr<V>,
|
||||
f: impl FnOnce(Interned<BitSlice>) -> Result<Interned<BitSlice>, HitUndeducedType>,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
Ok(v.to_literal_bits()?.and_then(f))
|
||||
}
|
||||
|
||||
fn binary_literal_bits<L: Value<Type: Type<Value = L>>, R: Value<Type: Type<Value = R>>>(
|
||||
l: Expr<L>,
|
||||
r: Expr<R>,
|
||||
f: impl FnOnce(Interned<BitSlice>, Interned<BitSlice>) -> Interned<BitSlice>,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
let l = l.to_literal_bits()?;
|
||||
let r = r.to_literal_bits()?;
|
||||
Ok((|| Ok(f(l?, r?)))())
|
||||
}
|
||||
|
||||
fn try_binary_literal_bits<L: Value<Type: Type<Value = L>>, R: Value<Type: Type<Value = R>>>(
|
||||
l: Expr<L>,
|
||||
r: Expr<R>,
|
||||
f: impl FnOnce(
|
||||
Interned<BitSlice>,
|
||||
Interned<BitSlice>,
|
||||
) -> Result<Interned<BitSlice>, HitUndeducedType>,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
let l = l.to_literal_bits()?;
|
||||
let r = r.to_literal_bits()?;
|
||||
Ok((|| f(l?, r?))())
|
||||
}
|
||||
|
||||
macro_rules! fixed_ary_op {
|
||||
(
|
||||
pub struct $name:ident<$($T:ident,)* $(#[const] $C:ident: $CTy:ty,)*>
|
||||
|
@ -56,7 +93,9 @@ macro_rules! fixed_ary_op {
|
|||
$($expr_enum_body:tt)+
|
||||
}
|
||||
|
||||
fn to_literal_bits(&$to_literal_bits_self:ident) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&$to_literal_bits_self:ident,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
$($to_literal_bits_body:tt)+
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +212,9 @@ macro_rules! fixed_ary_op {
|
|||
fn target(&self) -> Option<Interned<Target>> {
|
||||
($(self.$target_name,)? None::<Interned<Target>>,).0
|
||||
}
|
||||
fn to_literal_bits(&$to_literal_bits_self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&$to_literal_bits_self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
$($to_literal_bits_body)+
|
||||
}
|
||||
}
|
||||
|
@ -207,9 +248,8 @@ macro_rules! unary_op {
|
|||
Valueless::<$T>::from_canonical(arg.valueless()),
|
||||
).ty,
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
arg.to_literal_bits()
|
||||
.map(|v| ops::$Op::$op($T::CanonicalValue::from_bit_slice(&v)).to_bits())
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
|
||||
unary_literal_bits(arg, |v| ops::$Op::$op($T::CanonicalValue::from_bit_slice(&v)).to_bits())
|
||||
},
|
||||
|
||||
fn simulate(&self, sim_state: &mut SimState) -> _ {
|
||||
|
@ -220,7 +260,9 @@ macro_rules! unary_op {
|
|||
$($expr_enum_body)+
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -306,18 +348,14 @@ macro_rules! binary_op {
|
|||
Valueless::<$RhsType>::from_canonical(rhs.valueless()),
|
||||
).ty,
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
lhs.to_literal_bits()
|
||||
.ok()
|
||||
.zip(rhs.to_literal_bits().ok())
|
||||
.map(|(lhs, rhs)| {
|
||||
ops::$Op::$op(
|
||||
$LhsType::CanonicalValue::from_bit_slice(&lhs),
|
||||
$RhsType::CanonicalValue::from_bit_slice(&rhs),
|
||||
)
|
||||
.to_bits()
|
||||
})
|
||||
.ok_or(())
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
|
||||
binary_literal_bits(lhs, rhs, |lhs, rhs| {
|
||||
ops::$Op::$op(
|
||||
$LhsType::CanonicalValue::from_bit_slice(&lhs),
|
||||
$RhsType::CanonicalValue::from_bit_slice(&rhs),
|
||||
)
|
||||
.to_bits()
|
||||
})
|
||||
},
|
||||
fn simulate(&self, sim_state: &mut SimState) -> _ {
|
||||
ops::$Op::$op(self.lhs.simulate(sim_state), self.rhs.simulate(sim_state))
|
||||
|
@ -333,7 +371,9 @@ macro_rules! binary_op {
|
|||
ConstBoolDispatch::True(v) => ExprEnum::$expr_enum_s(v.intern_sized()),
|
||||
}
|
||||
}
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -539,18 +579,14 @@ macro_rules! dyn_shift_op {
|
|||
rhs.valueless(),
|
||||
).ty,
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
lhs.to_literal_bits()
|
||||
.ok()
|
||||
.zip(rhs.to_literal_bits().ok())
|
||||
.map(|(lhs, rhs)| {
|
||||
ops::$Op::$op(
|
||||
LhsType::CanonicalValue::from_bit_slice(&lhs),
|
||||
DynUInt::from_bit_slice(&rhs),
|
||||
)
|
||||
.to_bits()
|
||||
})
|
||||
.ok_or(())
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
|
||||
binary_literal_bits(lhs, rhs, |lhs, rhs| {
|
||||
ops::$Op::$op(
|
||||
LhsType::CanonicalValue::from_bit_slice(&lhs),
|
||||
DynUInt::from_bit_slice(&rhs),
|
||||
)
|
||||
.to_bits()
|
||||
})
|
||||
},
|
||||
fn simulate(&self, sim_state: &mut SimState) -> _ {
|
||||
ops::$Op::$op(self.lhs.simulate(sim_state), self.rhs.simulate(sim_state))
|
||||
|
@ -565,7 +601,9 @@ macro_rules! dyn_shift_op {
|
|||
ConstBoolDispatch::True(v) => ExprEnum::$expr_enum_s(v.intern_sized()),
|
||||
}
|
||||
}
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -646,15 +684,14 @@ macro_rules! fixed_shift_op {
|
|||
ty: <<Valueless<LhsType> as ops::$Op<usize>>::Output as ValuelessTr>::Type =
|
||||
ops::$Op::$op(lhs.valueless(), rhs).ty,
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
lhs.to_literal_bits()
|
||||
.map(|lhs| {
|
||||
ops::$Op::$op(
|
||||
LhsType::CanonicalValue::from_bit_slice(&lhs),
|
||||
rhs,
|
||||
)
|
||||
.to_bits()
|
||||
})
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
|
||||
unary_literal_bits(lhs, |lhs| {
|
||||
ops::$Op::$op(
|
||||
LhsType::CanonicalValue::from_bit_slice(&lhs),
|
||||
rhs,
|
||||
)
|
||||
.to_bits()
|
||||
})
|
||||
},
|
||||
fn simulate(&self, sim_state: &mut SimState) -> _ {
|
||||
ops::$Op::$op(self.lhs.simulate(sim_state), self.rhs)
|
||||
|
@ -669,7 +706,9 @@ macro_rules! fixed_shift_op {
|
|||
ConstBoolDispatch::True(v) => ExprEnum::$expr_enum_s(v.intern_sized()),
|
||||
}
|
||||
}
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -739,18 +778,14 @@ macro_rules! cmp_op {
|
|||
#[type]
|
||||
ty: Output = StaticOrDynIntType::new(),
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
lhs.to_literal_bits()
|
||||
.ok()
|
||||
.zip(rhs.to_literal_bits().ok())
|
||||
.map(|(lhs, rhs)| {
|
||||
interned_bit(
|
||||
LhsType::CanonicalValue::from_bit_slice(&lhs)
|
||||
.value()
|
||||
.$op(&RhsType::CanonicalValue::from_bit_slice(&rhs).value()),
|
||||
)
|
||||
})
|
||||
.ok_or(())
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
|
||||
binary_literal_bits(lhs, rhs, |lhs, rhs| {
|
||||
interned_bit(
|
||||
LhsType::CanonicalValue::from_bit_slice(&lhs)
|
||||
.value()
|
||||
.$op(&RhsType::CanonicalValue::from_bit_slice(&rhs).value()),
|
||||
)
|
||||
})
|
||||
},
|
||||
fn simulate(&self, sim_state: &mut SimState) -> _ {
|
||||
self.lhs.simulate(sim_state).$fn(self.rhs.simulate(sim_state)).into_canonical()
|
||||
|
@ -768,7 +803,9 @@ macro_rules! cmp_op {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -856,8 +893,8 @@ fixed_ary_op! {
|
|||
#[type(ty)]
|
||||
pub ty: ToType = ty,
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
value.to_literal_bits().map(|literal_bits| {
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
|
||||
unary_literal_bits(value, |literal_bits| {
|
||||
let mut bits = literal_bits.to_bitvec();
|
||||
let fill = FromType::Signed::VALUE
|
||||
&& bits.len().checked_sub(1).map(|i| bits[i]).unwrap_or(false);
|
||||
|
@ -901,7 +938,9 @@ fixed_ary_op! {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -956,8 +995,8 @@ fixed_ary_op! {
|
|||
#[type]
|
||||
ty: DynUIntType = base.valueless().slice(range.clone()).ty,
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
base.to_literal_bits().map(|base| {
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
|
||||
unary_literal_bits(base, |base| {
|
||||
base[range.clone()].intern()
|
||||
})
|
||||
},
|
||||
|
@ -976,7 +1015,9 @@ fixed_ary_op! {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -1110,8 +1151,8 @@ macro_rules! reduce_bit_op {
|
|||
#[type]
|
||||
ty: Output = StaticOrDynIntType::new(),
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
arg.to_literal_bits().map(|$bits| interned_bit($literal_bits_bool))
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
|
||||
unary_literal_bits(arg, |$bits| interned_bit($literal_bits_bool))
|
||||
},
|
||||
fn simulate(&self, sim_state: &mut SimState) -> _ {
|
||||
todo!()
|
||||
|
@ -1121,7 +1162,9 @@ macro_rules! reduce_bit_op {
|
|||
ExprEnum::$name($name::new_unchecked(self.arg).intern_sized())
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -1180,9 +1223,9 @@ fixed_ary_op! {
|
|||
Field::from_canonical_type(field_ty.expect("field type doesn't match type generic"))
|
||||
},
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
base.to_literal_bits().map(|base| {
|
||||
base[base_ty.field_offsets()[index]..][..field.ty.bit_width()].intern()
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
|
||||
try_unary_literal_bits(base, |base| {
|
||||
Ok(base[base_ty.field_offsets()[index]..][..field.ty.bit_width()?].intern())
|
||||
})
|
||||
},
|
||||
#[target]
|
||||
|
@ -1199,7 +1242,9 @@ fixed_ary_op! {
|
|||
ExprEnum::FieldAccess(FieldAccess::new_unchecked(self.base, self.name).intern_sized())
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -1239,9 +1284,9 @@ fixed_ary_op! {
|
|||
base_ty.variants()[variant_index].ty.unwrap_or_else(|| ().canonical_dyn()),
|
||||
),
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
base.to_literal_bits().map(|base| {
|
||||
base[base_ty.discriminant_bit_width()..][..ty.bit_width()].intern()
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
|
||||
try_unary_literal_bits(base, |base| {
|
||||
Ok(base[base_ty.discriminant_bit_width()..][..ty.bit_width()?].intern())
|
||||
})
|
||||
},
|
||||
fn simulate(&self, sim_state: &mut SimState) -> _ {
|
||||
|
@ -1255,7 +1300,9 @@ fixed_ary_op! {
|
|||
).intern_sized())
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -1292,7 +1339,7 @@ fixed_ary_op! {
|
|||
pub struct CastToBits<> where () {
|
||||
value: Expr<DynCanonicalValue>,
|
||||
#[type]
|
||||
ty: DynUIntType = DynUIntType::new(value.ty().bit_width()),
|
||||
ty: DynUIntType = DynUIntType::new(value.ty().bit_width().unwrap_or_else(|e| panic!("can't convert undeduced type to bits: {e}"))),
|
||||
fn simulate(&self, sim_state: &mut SimState) -> _ {
|
||||
todo!()
|
||||
}
|
||||
|
@ -1301,7 +1348,9 @@ fixed_ary_op! {
|
|||
ExprEnum::CastToBits(self.intern())
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.value.to_literal_bits()
|
||||
}
|
||||
}
|
||||
|
@ -1327,8 +1376,10 @@ fixed_ary_op! {
|
|||
value: Expr<DynUInt>,
|
||||
#[type(ty)]
|
||||
ty: T = {
|
||||
assert!(ty.is_castable_from_bits(), "can't cast bits to type: {ty:?}");
|
||||
assert_eq!(value.ty().width, ty.bit_width(), "input bit width didn't match target type's bit width");
|
||||
assert!(ty.is_castable_from_bits().unwrap_or(true), "can't cast bits to type: {ty:?}");
|
||||
if let Ok(bit_width) = ty.bit_width() {
|
||||
assert_eq!(value.ty().width, bit_width, "input bit width didn't match target type's bit width");
|
||||
}
|
||||
ty
|
||||
},
|
||||
fn simulate(&self, sim_state: &mut SimState) -> _ {
|
||||
|
@ -1341,7 +1392,9 @@ fixed_ary_op! {
|
|||
)
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.value.to_literal_bits()
|
||||
}
|
||||
}
|
||||
|
@ -1392,7 +1445,9 @@ macro_rules! cast_bit_to_typed_bit {
|
|||
ExprEnum::$Op($Op::new_unchecked(self.value).intern_sized())
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.value.to_literal_bits()
|
||||
}
|
||||
}
|
||||
|
@ -1552,17 +1607,18 @@ fixed_ary_op! {
|
|||
ty
|
||||
},
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
let mut bits = Some(BitVec::with_capacity(ty.bit_width()));
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = (|| {
|
||||
let mut bits = ty.bit_width().map(BitVec::with_capacity);
|
||||
for element in elements {
|
||||
let Ok(element_bits) = element.to_literal_bits() else {
|
||||
bits = None;
|
||||
break;
|
||||
};
|
||||
bits.as_mut().unwrap().extend_from_bitslice(&element_bits);
|
||||
let element_bits = element.to_literal_bits()?;
|
||||
match (&mut bits, element_bits) {
|
||||
(Ok(_), Err(e)) => bits = Err(e),
|
||||
(Err(_), _) => {}
|
||||
(Ok(bits), Ok(element_bits)) => bits.extend_from_bitslice(&element_bits),
|
||||
}
|
||||
}
|
||||
bits.map(Intern::intern_owned).ok_or(())
|
||||
},
|
||||
Ok(bits.map(Intern::intern_owned))
|
||||
})(),
|
||||
fn simulate(&self, sim_state: &mut SimState) -> _ {
|
||||
todo!()
|
||||
}
|
||||
|
@ -1571,7 +1627,9 @@ fixed_ary_op! {
|
|||
ExprEnum::ArrayLiteral(self.canonical().intern_sized())
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -1603,13 +1661,13 @@ fixed_ary_op! {
|
|||
base_ty.element().clone()
|
||||
},
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
|
||||
let base_ty = base.ty();
|
||||
let element_bit_width = base_ty.element().bit_width();
|
||||
base.to_literal_bits().map(|base| {
|
||||
try_unary_literal_bits(base, |base| {
|
||||
let element_bit_width = base_ty.element().bit_width()?;
|
||||
let start = index * element_bit_width;
|
||||
let end = start + element_bit_width;
|
||||
base[start..end].intern()
|
||||
Ok(base[start..end].intern())
|
||||
})
|
||||
},
|
||||
#[target]
|
||||
|
@ -1626,7 +1684,9 @@ fixed_ary_op! {
|
|||
ExprEnum::ArrayIndex(ArrayIndex::new_unchecked(self.base, self.index).intern_sized())
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -1655,18 +1715,32 @@ fixed_ary_op! {
|
|||
base_ty.element().clone()
|
||||
},
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = (|| {
|
||||
let base_ty = base.ty();
|
||||
let element_bit_width = base_ty.element().bit_width();
|
||||
base.to_literal_bits().ok().zip(index.to_literal_bits().ok()).and_then(|(base, index)| {
|
||||
let start = DynUInt::from_bit_slice(&index)
|
||||
.uint_value()
|
||||
.to_usize()?
|
||||
.checked_mul(element_bit_width)?;
|
||||
let end = start.checked_add(element_bit_width)?;
|
||||
Some(base.get(start..end)?.intern())
|
||||
}).ok_or(())
|
||||
},
|
||||
let base = base.to_literal_bits()?;
|
||||
let index = index.to_literal_bits()?;
|
||||
let element_bit_width = match base_ty.element().bit_width() {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Ok(Err(e)),
|
||||
};
|
||||
let base = match base {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Ok(Err(e)),
|
||||
};
|
||||
let index = match index {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Ok(Err(e)),
|
||||
};
|
||||
let start = DynUInt::from_bit_slice(&index)
|
||||
.uint_value()
|
||||
.to_usize()
|
||||
.and_then(|v| v.checked_mul(element_bit_width));
|
||||
let end = start.and_then(|v| v.checked_add(element_bit_width));
|
||||
start
|
||||
.zip(end)
|
||||
.and_then(|(start, end)| Some(Ok(base.get(start..end)?.intern())))
|
||||
.ok_or(NotALiteralExpr)
|
||||
})(),
|
||||
#[target]
|
||||
target: Option<Interned<Target>> = base.target().map(|base| {
|
||||
Intern::intern_sized(base.join(
|
||||
|
@ -1683,7 +1757,9 @@ fixed_ary_op! {
|
|||
)
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -1728,7 +1804,7 @@ impl<
|
|||
|
||||
fn expr_index(this: Expr<Self>, index: Expr<IntValue<Idx>>) -> Expr<Self::OutputValue> {
|
||||
let index: Expr<DynUInt> = index.canonical();
|
||||
if let Ok(index) = index.to_literal_bits() {
|
||||
if let Ok(Ok(index)) = index.to_literal_bits() {
|
||||
let index = DynUInt::from_bit_slice(&index)
|
||||
.uint_value()
|
||||
.try_into()
|
||||
|
@ -1758,7 +1834,7 @@ fixed_ary_op! {
|
|||
#[type(ty)]
|
||||
ty: BundleTy = {
|
||||
assert!(
|
||||
ty.is_passive(),
|
||||
ty.is_passive().unwrap_or(true),
|
||||
concat!(
|
||||
"bundle literal must be a passive type (no ",
|
||||
"#[flip] fields and all fields must be passive types)",
|
||||
|
@ -1775,17 +1851,18 @@ fixed_ary_op! {
|
|||
ty
|
||||
},
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> = {
|
||||
let mut bits = Some(BitVec::new());
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = (|| {
|
||||
let mut bits = ty.bit_width().map(BitVec::with_capacity);
|
||||
for field in fields {
|
||||
let Ok(v) = field.to_literal_bits() else {
|
||||
bits = None;
|
||||
break;
|
||||
};
|
||||
bits.as_mut().unwrap().extend_from_bitslice(&v);
|
||||
let field_bits = field.to_literal_bits()?;
|
||||
match (&mut bits, field_bits) {
|
||||
(Ok(_), Err(e)) => bits = Err(e),
|
||||
(Err(_), _) => {}
|
||||
(Ok(bits), Ok(field_bits)) => bits.extend_from_bitslice(&field_bits),
|
||||
}
|
||||
}
|
||||
bits.map(Intern::intern_owned).ok_or(())
|
||||
},
|
||||
Ok(bits.map(Intern::intern_owned))
|
||||
})(),
|
||||
fn simulate(&self, sim_state: &mut SimState) -> _ {
|
||||
todo!()
|
||||
}
|
||||
|
@ -1794,7 +1871,9 @@ fixed_ary_op! {
|
|||
ExprEnum::BundleLiteral(self.canonical().intern_sized())
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
@ -1831,7 +1910,7 @@ fixed_ary_op! {
|
|||
ty
|
||||
},
|
||||
#[cache]
|
||||
literal_bits: Result<Interned<BitSlice>, ()> =
|
||||
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> =
|
||||
ty.variant_to_bits(variant_index, variant_value.as_ref()),
|
||||
fn simulate(&self, sim_state: &mut SimState) -> _ {
|
||||
todo!()
|
||||
|
@ -1841,7 +1920,9 @@ fixed_ary_op! {
|
|||
ExprEnum::EnumLiteral(self.canonical().intern_sized())
|
||||
}
|
||||
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
|
||||
fn to_literal_bits(
|
||||
&self,
|
||||
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
|
||||
self.literal_bits
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ use crate::{
|
|||
DynCanonicalType, DynCanonicalValue, DynCanonicalValueTrait, DynType, DynValue, Type,
|
||||
TypeEnum, Value, ValueEnum,
|
||||
},
|
||||
type_deduction::HitUndeducedType,
|
||||
util::{
|
||||
const_str_array_is_strictly_ascending, BitSliceWriteWithBase, DebugAsRawString,
|
||||
GenericConstBool,
|
||||
|
@ -440,6 +441,7 @@ impl TypeState {
|
|||
TypeEnum::AsyncReset(AsyncResetType {}) => "AsyncReset".into(),
|
||||
TypeEnum::SyncReset(SyncResetType {}) => "UInt<1>".into(),
|
||||
TypeEnum::Reset(ResetType {}) => "Reset".into(),
|
||||
TypeEnum::Deduce(_) => handle_undeduced_type(HitUndeducedType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -468,6 +470,25 @@ impl Default for ModuleState {
|
|||
|
||||
struct WrappedError;
|
||||
|
||||
fn handle_undeduced_type(e: HitUndeducedType) -> ! {
|
||||
panic!("can't export module with undeduced types: {e}")
|
||||
}
|
||||
|
||||
trait UnwrapUndeduced {
|
||||
type Output;
|
||||
fn unwrap_undeduced(self) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<T> UnwrapUndeduced for Result<T, HitUndeducedType> {
|
||||
type Output = T;
|
||||
fn unwrap_undeduced(self) -> Self::Output {
|
||||
match self {
|
||||
Ok(v) => v,
|
||||
Err(e) => handle_undeduced_type(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait WrappedFileBackendTrait {
|
||||
fn write_mem_init_file(
|
||||
&mut self,
|
||||
|
@ -1012,10 +1033,12 @@ impl<'a> Exporter<'a> {
|
|||
name,
|
||||
flipped: _,
|
||||
ty: field_ty,
|
||||
}| FieldType {
|
||||
name,
|
||||
flipped: false,
|
||||
ty: DynUIntType::new(field_ty.bit_width()).canonical_dyn(),
|
||||
}| {
|
||||
FieldType {
|
||||
name,
|
||||
flipped: false,
|
||||
ty: DynUIntType::new(field_ty.bit_width().unwrap_undeduced()).canonical_dyn(),
|
||||
}
|
||||
},
|
||||
)));
|
||||
let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty);
|
||||
|
@ -1047,7 +1070,7 @@ impl<'a> Exporter<'a> {
|
|||
let retval = self.module.ns.make_new("_cast_to_bits_expr");
|
||||
definitions.add_definition_line(format_args!(
|
||||
"{extra_indent}wire {retval}: UInt<{}>",
|
||||
ty.bit_width()
|
||||
ty.bit_width().unwrap_undeduced()
|
||||
));
|
||||
let cat_expr = cat_expr.expect("bundle already checked to have fields");
|
||||
definitions.add_definition_line(format_args!("{extra_indent}connect {retval}, {cat_expr}"));
|
||||
|
@ -1066,7 +1089,7 @@ impl<'a> Exporter<'a> {
|
|||
let retval = self.module.ns.make_new("_cast_enum_to_bits_expr");
|
||||
definitions.add_definition_line(format_args!(
|
||||
"{extra_indent}wire {retval}: UInt<{}>",
|
||||
ty.bit_width()
|
||||
ty.bit_width().unwrap_undeduced()
|
||||
));
|
||||
definitions.add_definition_line(format_args!("{extra_indent}match {value_str}:"));
|
||||
let _match_arms_indent = extra_indent.push();
|
||||
|
@ -1090,7 +1113,7 @@ impl<'a> Exporter<'a> {
|
|||
definitions.add_definition_line(format_args!(
|
||||
"{extra_indent}connect {retval}, pad(cat({variant_bits}, UInt<{}>({variant_index})), {})",
|
||||
ty.discriminant_bit_width(),
|
||||
ty.bit_width(),
|
||||
ty.bit_width().unwrap_undeduced(),
|
||||
));
|
||||
} else {
|
||||
definitions.add_definition_line(format_args!(
|
||||
|
@ -1100,7 +1123,7 @@ impl<'a> Exporter<'a> {
|
|||
let _match_arm_indent = extra_indent.push();
|
||||
definitions.add_definition_line(format_args!(
|
||||
"{extra_indent}connect {retval}, UInt<{}>({variant_index})",
|
||||
ty.bit_width(),
|
||||
ty.bit_width().unwrap_undeduced(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -1124,7 +1147,7 @@ impl<'a> Exporter<'a> {
|
|||
extra_indent,
|
||||
);
|
||||
}
|
||||
let element_width = ty.element().bit_width();
|
||||
let element_width = ty.element().bit_width().unwrap_undeduced();
|
||||
let ident = self.module.ns.make_new("_cast_array_to_bits_expr");
|
||||
definitions.add_definition_line(format_args!(
|
||||
"{extra_indent}wire {ident}: UInt<{element_width}>[{}]",
|
||||
|
@ -1150,7 +1173,7 @@ impl<'a> Exporter<'a> {
|
|||
let retval = self.module.ns.make_new("_cast_to_bits_expr");
|
||||
definitions.add_definition_line(format_args!(
|
||||
"{extra_indent}wire {retval}: UInt<{}>",
|
||||
ty.bit_width()
|
||||
ty.bit_width().unwrap_undeduced()
|
||||
));
|
||||
let cat_expr = cat_expr.expect("array already checked to have elements");
|
||||
definitions.add_definition_line(format_args!("{extra_indent}connect {retval}, {cat_expr}"));
|
||||
|
@ -1178,6 +1201,7 @@ impl<'a> Exporter<'a> {
|
|||
| TypeEnum::Clock(_)
|
||||
| TypeEnum::AsyncReset(_)
|
||||
| TypeEnum::Reset(_) => format!("asUInt({value_str})"),
|
||||
TypeEnum::Deduce(_) => handle_undeduced_type(HitUndeducedType),
|
||||
}
|
||||
}
|
||||
fn expr_cast_bits_to_bundle(
|
||||
|
@ -1199,10 +1223,12 @@ impl<'a> Exporter<'a> {
|
|||
name,
|
||||
flipped: _,
|
||||
ty: field_ty,
|
||||
}| FieldType {
|
||||
name,
|
||||
flipped: false,
|
||||
ty: DynUIntType::new(field_ty.bit_width()).canonical_dyn(),
|
||||
}| {
|
||||
FieldType {
|
||||
name,
|
||||
flipped: false,
|
||||
ty: DynUIntType::new(field_ty.bit_width().unwrap_undeduced()).canonical_dyn(),
|
||||
}
|
||||
},
|
||||
)));
|
||||
let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty);
|
||||
|
@ -1218,7 +1244,9 @@ impl<'a> Exporter<'a> {
|
|||
.type_state
|
||||
.get_bundle_field(flattened_bundle_ty, field.name);
|
||||
let field_ident = self.type_state.get_bundle_field(ty, field.name);
|
||||
if let Some(field_bit_width_minus_one) = field.ty.bit_width().checked_sub(1usize) {
|
||||
if let Some(field_bit_width_minus_one) =
|
||||
field.ty.bit_width().unwrap_undeduced().checked_sub(1usize)
|
||||
{
|
||||
definitions.add_definition_line(format_args!(
|
||||
"{extra_indent}connect {flattened_ident}.{flattened_field_ident}, bits({value_str}, {}, {field_offset})",
|
||||
field_offset + field_bit_width_minus_one
|
||||
|
@ -1272,7 +1300,7 @@ impl<'a> Exporter<'a> {
|
|||
return retval.to_string();
|
||||
}
|
||||
let discriminant_bit_width = ty.discriminant_bit_width();
|
||||
let body_bit_width = ty.bit_width() - discriminant_bit_width;
|
||||
let body_bit_width = ty.bit_width().unwrap_undeduced() - discriminant_bit_width;
|
||||
let body_ident = self.module.ns.make_new("_cast_bits_to_enum_expr_body");
|
||||
let body_value = if body_bit_width != 0 {
|
||||
definitions.add_definition_line(format_args!(
|
||||
|
@ -1328,7 +1356,7 @@ impl<'a> Exporter<'a> {
|
|||
let retval = self.module.ns.make_new("_cast_bits_to_array_expr");
|
||||
let array_ty = self.type_state.ty(ty);
|
||||
definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {array_ty}"));
|
||||
let element_bit_width = ty.element().bit_width();
|
||||
let element_bit_width = ty.element().bit_width().unwrap_undeduced();
|
||||
if ty.is_empty() || element_bit_width == 0 {
|
||||
definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}"));
|
||||
return retval.to_string();
|
||||
|
@ -1382,6 +1410,7 @@ impl<'a> Exporter<'a> {
|
|||
TypeEnum::AsyncReset(_) => format!("asAsyncReset({value_str})"),
|
||||
TypeEnum::SyncReset(_) => value_str,
|
||||
TypeEnum::Reset(_) => unreachable!("Reset is not bit castable to"),
|
||||
TypeEnum::Deduce(_) => handle_undeduced_type(HitUndeducedType),
|
||||
}
|
||||
}
|
||||
fn expr_unary<V: Value<Type: Type<Value = V>>>(
|
||||
|
@ -1673,13 +1702,13 @@ impl<'a> Exporter<'a> {
|
|||
) -> Result<(), WrappedError> {
|
||||
assert_eq!(
|
||||
initial_value.len(),
|
||||
array_type.bit_width(),
|
||||
array_type.bit_width().unwrap_undeduced(),
|
||||
"literal bits don't match memory array type bit width"
|
||||
);
|
||||
if initial_value.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let element_bit_width = array_type.element().bit_width();
|
||||
let element_bit_width = array_type.element().bit_width().unwrap_undeduced();
|
||||
let mut contents = String::new();
|
||||
let hex_or_binary = if element_bit_width % 4 == 0 {
|
||||
HexOrBinary::Hex
|
||||
|
@ -2391,7 +2420,7 @@ fn export_impl(
|
|||
file_backend: &mut dyn WrappedFileBackendTrait,
|
||||
top_module: Interned<Module<DynBundle>>,
|
||||
) -> Result<(), WrappedError> {
|
||||
let top_module = simplify_memories(top_module);
|
||||
let top_module = simplify_memories(top_module).unwrap_undeduced();
|
||||
let indent_depth = Cell::new(0);
|
||||
let mut global_ns = Namespace::default();
|
||||
let circuit_name = global_ns.get(top_module.name_id());
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::{
|
|||
impl_match_values_as_self, CanonicalType, CanonicalTypeKind, CanonicalValue, Connect,
|
||||
DynCanonicalType, StaticType, Type, TypeEnum, Value, ValueEnum,
|
||||
},
|
||||
type_deduction::{HitUndeducedType, UndeducedType},
|
||||
util::{ConstBool, GenericConstBool},
|
||||
valueless::Valueless,
|
||||
};
|
||||
|
@ -339,22 +340,7 @@ impl<
|
|||
// 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<<Ty as IntTypeTrait>::Signed>,
|
||||
CanonicalValue = DynInt<<Ty as IntTypeTrait>::Signed>,
|
||||
>,
|
||||
> Value for IntValue<Ty>
|
||||
{
|
||||
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
|
||||
IntValue {
|
||||
ty: self.ty.canonical(),
|
||||
uint_value: self.uint_value.clone(),
|
||||
}
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
pub fn to_bits(&self) -> Interned<BitSlice> {
|
||||
#[derive(Hash, Eq, PartialEq)]
|
||||
struct ToBitsMemoize<T>(PhantomData<T>);
|
||||
impl<T> Clone for ToBitsMemoize<T> {
|
||||
|
@ -387,7 +373,25 @@ impl<
|
|||
Intern::intern_owned(bits)
|
||||
}
|
||||
}
|
||||
ToBitsMemoize::<Self>(PhantomData).get(this)
|
||||
ToBitsMemoize::<Self>(PhantomData).get(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Ty: IntTypeTrait<
|
||||
CanonicalType = DynIntType<<Ty as IntTypeTrait>::Signed>,
|
||||
CanonicalValue = DynInt<<Ty as IntTypeTrait>::Signed>,
|
||||
>,
|
||||
> Value for IntValue<Ty>
|
||||
{
|
||||
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
|
||||
IntValue {
|
||||
ty: self.ty.canonical(),
|
||||
uint_value: self.uint_value.clone(),
|
||||
}
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
Ok(IntValue::to_bits(this))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1111,6 +1115,8 @@ impl DynSIntType {
|
|||
|
||||
impl<Signed: GenericConstBool> sealed::Sealed for DynIntType<Signed> {}
|
||||
|
||||
impl<Signed: GenericConstBool> Connect<UndeducedType> for DynIntType<Signed> {}
|
||||
|
||||
impl<Signed: GenericConstBool> Type for DynIntType<Signed> {
|
||||
type CanonicalType = DynIntType<Signed>;
|
||||
type Value = IntValue<DynIntType<Signed>>;
|
||||
|
@ -1176,7 +1182,7 @@ impl<Signed: GenericConstBool> CanonicalValue for IntValue<DynIntType<Signed>> {
|
|||
ValueEnum::UInt(this.clone().as_same_width_uint())
|
||||
}
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
<Self as Value>::to_bits_impl(this)
|
||||
}
|
||||
}
|
||||
|
@ -1203,7 +1209,9 @@ impl<Signed: GenericConstBool> IntTypeTrait for DynIntType<Signed> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Signed: GenericConstBool, const WIDTH: usize> StaticOrDynIntType<WIDTH> for DynIntType<Signed> {
|
||||
impl<Signed: GenericConstBool, const WIDTH: usize> StaticOrDynIntType<WIDTH>
|
||||
for DynIntType<Signed>
|
||||
{
|
||||
fn new() -> Self {
|
||||
DynIntType::new(WIDTH)
|
||||
}
|
||||
|
@ -1233,6 +1241,11 @@ pub type SIntType<const WIDTH: usize> = IntType<ConstBool<true>, WIDTH>;
|
|||
|
||||
impl<Signed: GenericConstBool, const WIDTH: usize> sealed::Sealed for IntType<Signed, WIDTH> {}
|
||||
|
||||
impl<Signed: GenericConstBool, const WIDTH: usize> Connect<UndeducedType>
|
||||
for IntType<Signed, WIDTH>
|
||||
{
|
||||
}
|
||||
|
||||
impl<Signed: GenericConstBool, const WIDTH: usize> Type for IntType<Signed, WIDTH> {
|
||||
type CanonicalType = DynIntType<Signed>;
|
||||
type Value = IntValue<IntType<Signed, WIDTH>>;
|
||||
|
|
|
@ -40,6 +40,7 @@ pub mod reg;
|
|||
pub mod reset;
|
||||
pub mod source_location;
|
||||
pub mod ty;
|
||||
pub mod type_deduction;
|
||||
pub mod util;
|
||||
pub mod valueless;
|
||||
pub mod wire;
|
||||
|
|
|
@ -13,6 +13,7 @@ use crate::{
|
|||
module::ScopedNameId,
|
||||
source_location::SourceLocation,
|
||||
ty::{AsMask, DynCanonicalType, DynCanonicalValue, DynType, Type, Value},
|
||||
type_deduction::HitUndeducedType,
|
||||
util::DebugAsDisplay,
|
||||
};
|
||||
use bitvec::slice::BitSlice;
|
||||
|
@ -492,7 +493,7 @@ impl<T: PortType> MemPort<T> {
|
|||
mem_element_type: Interned<dyn DynCanonicalType>,
|
||||
) -> Self {
|
||||
assert!(
|
||||
mem_element_type.is_storable(),
|
||||
mem_element_type.is_storable().unwrap_or(true),
|
||||
"memory element type must be a storable type"
|
||||
);
|
||||
Self {
|
||||
|
@ -626,7 +627,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> Mem<VA> {
|
|||
let addr_width = memory_addr_width(array_type.len());
|
||||
let expected_mem_element_type = array_type.element().canonical_dyn();
|
||||
assert!(
|
||||
expected_mem_element_type.is_storable(),
|
||||
expected_mem_element_type.is_storable().unwrap_or(true),
|
||||
"memory element type must be a storable type"
|
||||
);
|
||||
for (index, port) in ports.iter().enumerate() {
|
||||
|
@ -846,19 +847,21 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
|
|||
initial_value: Interned<BitSlice>,
|
||||
) -> Interned<BitSlice> {
|
||||
if let Some(depth) = depth {
|
||||
let expected_len = depth.checked_mul(mem_element_type.bit_width()).expect(
|
||||
"memory must be small enough that its initializer bit length fits in usize",
|
||||
);
|
||||
assert_eq!(
|
||||
expected_len,
|
||||
initial_value.len(),
|
||||
"Mem's initializer bit length doesn't match the expected value",
|
||||
);
|
||||
if let Ok(mem_element_bit_width) = mem_element_type.bit_width() {
|
||||
let expected_len = depth.checked_mul(mem_element_bit_width).expect(
|
||||
"memory must be small enough that its initializer bit length fits in usize",
|
||||
);
|
||||
assert_eq!(
|
||||
expected_len,
|
||||
initial_value.len(),
|
||||
"Mem's initializer bit length doesn't match the expected value",
|
||||
);
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
initial_value
|
||||
.len()
|
||||
.checked_rem(mem_element_type.bit_width())
|
||||
.checked_rem(mem_element_type.bit_width().unwrap_or(1))
|
||||
.unwrap_or(initial_value.len())
|
||||
== 0,
|
||||
"Mem's initializer bit length must be a multiple of the element type's bit width",
|
||||
|
@ -887,8 +890,17 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
|
|||
let Ok(retval) = initial_value.to_literal_bits() else {
|
||||
panic!("Mem's initializer must be convertible to literal bits");
|
||||
};
|
||||
let retval = match retval {
|
||||
Ok(retval) => retval,
|
||||
Err(HitUndeducedType { .. }) => {
|
||||
todo!(
|
||||
"Mem's initializer contains undeduced types, \
|
||||
you can work around this by using only hdl(static) types"
|
||||
)
|
||||
}
|
||||
};
|
||||
debug_assert_eq!(
|
||||
retval.len(),
|
||||
Ok(retval.len()),
|
||||
initial_value_ty.bit_width(),
|
||||
"initial value produced wrong literal bits length"
|
||||
);
|
||||
|
@ -902,7 +914,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
|
|||
) -> (Self, Rc<RefCell<MemBuilderTarget>>) {
|
||||
let canonical_mem_element_type = mem_element_type.canonical_dyn();
|
||||
assert!(
|
||||
canonical_mem_element_type.is_storable(),
|
||||
canonical_mem_element_type.is_storable().unwrap_or(true),
|
||||
"memory element type must be a storable type"
|
||||
);
|
||||
let target = Rc::new(RefCell::new(MemBuilderTarget {
|
||||
|
@ -1061,9 +1073,10 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
|
|||
target.depth,
|
||||
initial_value,
|
||||
));
|
||||
let element_bit_width = self.mem_element_type.bit_width();
|
||||
if element_bit_width != 0 {
|
||||
target.depth = Some(initial_value.len() / element_bit_width);
|
||||
if let Ok(element_bit_width) = self.mem_element_type.bit_width() {
|
||||
if element_bit_width != 0 {
|
||||
target.depth = Some(initial_value.len() / element_bit_width);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn get_read_latency(&self) -> usize {
|
||||
|
|
|
@ -20,6 +20,7 @@ use crate::{
|
|||
CanonicalType, Connect, DynCanonicalType, DynCanonicalValue, DynType, StaticValue, Type,
|
||||
TypeEnum, Value,
|
||||
},
|
||||
type_deduction::HitUndeducedType,
|
||||
util::ConstBool,
|
||||
wire::Wire,
|
||||
};
|
||||
|
@ -1414,42 +1415,42 @@ impl TargetState {
|
|||
}
|
||||
}
|
||||
}
|
||||
fn new(target: Interned<Target>, declared_in_block: usize) -> Self {
|
||||
Self {
|
||||
fn new(target: Interned<Target>, declared_in_block: usize) -> Result<Self, HitUndeducedType> {
|
||||
Ok(Self {
|
||||
target,
|
||||
inner: match target.canonical_ty().type_enum() {
|
||||
TypeEnum::BundleType(ty) => TargetStateInner::Decomposed {
|
||||
subtargets: ty
|
||||
.fields()
|
||||
.iter()
|
||||
.map(|&field| {
|
||||
.map(|&field| -> Result<_, HitUndeducedType> {
|
||||
let path_element = TargetPathElement::intern_sized(
|
||||
TargetPathBundleField { name: field.name }.into(),
|
||||
);
|
||||
(
|
||||
Ok((
|
||||
path_element,
|
||||
Self::new(
|
||||
Target::intern_sized(target.join(path_element)),
|
||||
declared_in_block,
|
||||
),
|
||||
)
|
||||
)?,
|
||||
))
|
||||
})
|
||||
.collect(),
|
||||
.collect::<Result<_, _>>()?,
|
||||
},
|
||||
TypeEnum::ArrayType(ty) => TargetStateInner::Decomposed {
|
||||
subtargets: (0..ty.len())
|
||||
.map(|index| {
|
||||
.map(|index| -> Result<_, HitUndeducedType> {
|
||||
let path_element =
|
||||
Intern::intern_sized(TargetPathArrayElement { index }.into());
|
||||
(
|
||||
Ok((
|
||||
path_element,
|
||||
Self::new(
|
||||
Target::intern_sized(target.join(path_element)),
|
||||
declared_in_block,
|
||||
),
|
||||
)
|
||||
)?,
|
||||
))
|
||||
})
|
||||
.collect(),
|
||||
.collect::<Result<_, _>>()?,
|
||||
},
|
||||
TypeEnum::EnumType(_)
|
||||
| TypeEnum::UInt(_)
|
||||
|
@ -1461,8 +1462,9 @@ impl TargetState {
|
|||
declared_in_block,
|
||||
written_in_blocks: RefCell::default(),
|
||||
},
|
||||
TypeEnum::Deduce(_) => return Err(HitUndeducedType),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1524,7 +1526,11 @@ impl AssertValidityState {
|
|||
self.target_states.get(&target_base).ok_or(())
|
||||
}
|
||||
#[track_caller]
|
||||
fn insert_new_base(&mut self, target_base: Interned<TargetBase>, declared_in_block: usize) {
|
||||
fn insert_new_base(
|
||||
&mut self,
|
||||
target_base: Interned<TargetBase>,
|
||||
declared_in_block: usize,
|
||||
) -> Result<(), HitUndeducedType> {
|
||||
match self.target_states.entry(target_base) {
|
||||
Entry::Occupied(_) => panic!(
|
||||
"at {}: duplicate declaration: {target_base}",
|
||||
|
@ -1534,9 +1540,10 @@ impl AssertValidityState {
|
|||
entry.insert(TargetState::new(
|
||||
Target::intern_sized(target_base.into()),
|
||||
declared_in_block,
|
||||
));
|
||||
)?);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn set_connect_target_written(
|
||||
target_state: &TargetState,
|
||||
|
@ -1625,29 +1632,30 @@ impl AssertValidityState {
|
|||
&mut self,
|
||||
parent_block: usize,
|
||||
sub_blocks: impl Clone + IntoIterator<Item = usize>,
|
||||
) {
|
||||
) -> Result<(), HitUndeducedType> {
|
||||
for i in sub_blocks.clone() {
|
||||
self.assert_subtree_validity(i);
|
||||
self.assert_subtree_validity(i)?;
|
||||
}
|
||||
for i in self.target_states.values() {
|
||||
i.merge_conditional_sub_blocks_into_block(parent_block, sub_blocks.clone());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[track_caller]
|
||||
fn assert_subtree_validity(&mut self, block: usize) {
|
||||
fn assert_subtree_validity(&mut self, block: usize) -> Result<(), HitUndeducedType> {
|
||||
let module = self.module;
|
||||
if block == 0 {
|
||||
for module_io in &*module.module_io {
|
||||
self.insert_new_base(
|
||||
TargetBase::intern_sized(module_io.module_io.clone().into()),
|
||||
block,
|
||||
);
|
||||
)?;
|
||||
}
|
||||
}
|
||||
let Block { memories, stmts } = self.blocks[block];
|
||||
for m in memories {
|
||||
for port in m.ports() {
|
||||
self.insert_new_base(TargetBase::intern_sized((*port).into()), block);
|
||||
self.insert_new_base(TargetBase::intern_sized((*port).into()), block)?;
|
||||
}
|
||||
}
|
||||
for stmt in stmts {
|
||||
|
@ -1662,7 +1670,7 @@ impl AssertValidityState {
|
|||
}
|
||||
Stmt::If(if_stmt) => {
|
||||
let sub_blocks = if_stmt.blocks.map(|block| self.make_block_index(block));
|
||||
self.process_conditional_sub_blocks(block, sub_blocks)
|
||||
self.process_conditional_sub_blocks(block, sub_blocks)?
|
||||
}
|
||||
Stmt::Match(match_stmt) => {
|
||||
let sub_blocks = Vec::from_iter(
|
||||
|
@ -1671,22 +1679,23 @@ impl AssertValidityState {
|
|||
.into_iter()
|
||||
.map(|block| self.make_block_index(block)),
|
||||
);
|
||||
self.process_conditional_sub_blocks(block, sub_blocks.iter().copied())
|
||||
self.process_conditional_sub_blocks(block, sub_blocks.iter().copied())?
|
||||
}
|
||||
Stmt::Declaration(StmtDeclaration::Wire(StmtWire {
|
||||
annotations: _,
|
||||
wire,
|
||||
})) => self.insert_new_base(TargetBase::intern_sized(wire.into()), block),
|
||||
})) => self.insert_new_base(TargetBase::intern_sized(wire.into()), block)?,
|
||||
Stmt::Declaration(StmtDeclaration::Reg(StmtReg {
|
||||
annotations: _,
|
||||
reg,
|
||||
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
|
||||
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block)?,
|
||||
Stmt::Declaration(StmtDeclaration::Instance(StmtInstance {
|
||||
annotations: _,
|
||||
instance,
|
||||
})) => self.insert_new_base(TargetBase::intern_sized(instance.into()), block),
|
||||
})) => self.insert_new_base(TargetBase::intern_sized(instance.into()), block)?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
#[track_caller]
|
||||
fn assert_validity(&mut self) {
|
||||
|
@ -1698,10 +1707,11 @@ impl AssertValidityState {
|
|||
ModuleBody::Normal(NormalModuleBody { body }) => {
|
||||
let body = self.make_block_index(body);
|
||||
assert_eq!(body, 0);
|
||||
self.assert_subtree_validity(body);
|
||||
for (base, state) in &self.target_states {
|
||||
if base.must_connect_to() {
|
||||
state.assert_written();
|
||||
if let Ok(()) = self.assert_subtree_validity(body) {
|
||||
for (base, state) in &self.target_states {
|
||||
if base.must_connect_to() {
|
||||
state.assert_written();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2367,7 +2377,7 @@ where
|
|||
match rhs.flow() {
|
||||
Flow::Source | Flow::Duplex => {}
|
||||
Flow::Sink => assert!(
|
||||
rhs.ty().is_passive(),
|
||||
rhs.ty().is_passive().unwrap_or(true),
|
||||
"can't connect from sink with non-passive type"
|
||||
),
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use crate::{
|
|||
},
|
||||
source_location::SourceLocation,
|
||||
ty::{DynCanonicalType, DynCanonicalValue, Type, TypeEnum, Value, ValueEnum},
|
||||
type_deduction::HitUndeducedType,
|
||||
wire::Wire,
|
||||
};
|
||||
use core::fmt;
|
||||
|
@ -22,6 +23,7 @@ use hashbrown::HashMap;
|
|||
#[derive(Debug)]
|
||||
pub enum SimplifyEnumsError {
|
||||
EnumIsNotCastableFromBits { enum_type: DynEnumType },
|
||||
HitUndeducedType(HitUndeducedType),
|
||||
}
|
||||
|
||||
impl fmt::Display for SimplifyEnumsError {
|
||||
|
@ -31,12 +33,19 @@ impl fmt::Display for SimplifyEnumsError {
|
|||
f,
|
||||
"simplify_enums failed: enum type is not castable from bits: {enum_type:?}"
|
||||
),
|
||||
SimplifyEnumsError::HitUndeducedType(e) => e.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for SimplifyEnumsError {}
|
||||
|
||||
impl From<HitUndeducedType> for SimplifyEnumsError {
|
||||
fn from(value: HitUndeducedType) -> Self {
|
||||
Self::HitUndeducedType(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Value, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
struct TagAndBody<T> {
|
||||
tag: T,
|
||||
|
@ -69,7 +78,7 @@ impl State {
|
|||
if let Some(retval) = self.enum_types.get(&enum_type) {
|
||||
return Ok(retval.clone());
|
||||
}
|
||||
if !enum_type.is_castable_from_bits() {
|
||||
if !enum_type.is_castable_from_bits()? {
|
||||
return Err(SimplifyEnumsError::EnumIsNotCastableFromBits { enum_type });
|
||||
}
|
||||
let has_body = enum_type
|
||||
|
@ -86,7 +95,7 @@ impl State {
|
|||
},
|
||||
))),
|
||||
body: DynUIntType::new(
|
||||
enum_type.bit_width() - enum_type.discriminant_bit_width(),
|
||||
enum_type.bit_width()? - enum_type.discriminant_bit_width(),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
@ -95,12 +104,12 @@ impl State {
|
|||
EnumTypeState::TagUIntAndBody(TagAndBodyType::<DynUInt> {
|
||||
tag: DynUIntType::new(enum_type.discriminant_bit_width()),
|
||||
body: DynUIntType::new(
|
||||
enum_type.bit_width() - enum_type.discriminant_bit_width(),
|
||||
enum_type.bit_width()? - enum_type.discriminant_bit_width(),
|
||||
),
|
||||
})
|
||||
}
|
||||
(SimplifyEnumsKind::ReplaceWithUInt, _) => {
|
||||
EnumTypeState::UInt(DynUIntType::new(enum_type.bit_width()))
|
||||
EnumTypeState::UInt(DynUIntType::new(enum_type.bit_width()?))
|
||||
}
|
||||
};
|
||||
self.enum_types.insert(enum_type, retval.clone());
|
||||
|
@ -108,11 +117,14 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
fn value_to_uint<T: Value>(value: Option<&T>, target_ty: DynUIntType) -> DynUInt {
|
||||
fn value_to_uint<T: Value>(
|
||||
value: Option<&T>,
|
||||
target_ty: DynUIntType,
|
||||
) -> Result<DynUInt, HitUndeducedType> {
|
||||
let Some(value) = value else {
|
||||
return DynUInt::with_type(target_ty, 0u8);
|
||||
return Ok(DynUInt::with_type(target_ty, 0u8));
|
||||
};
|
||||
DynUInt::from_bit_slice(&value.to_bits())
|
||||
Ok(DynUInt::from_bit_slice(&value.to_bits()?))
|
||||
}
|
||||
|
||||
fn connect_port(
|
||||
|
@ -120,7 +132,7 @@ fn connect_port(
|
|||
lhs: Expr<DynCanonicalValue>,
|
||||
rhs: Expr<DynCanonicalValue>,
|
||||
source_location: SourceLocation,
|
||||
) {
|
||||
) -> Result<(), HitUndeducedType> {
|
||||
println!("connect_port: lhs={lhs:?} rhs={rhs:?}");
|
||||
if lhs.canonical_type() == rhs.canonical_type() {
|
||||
stmts.push(
|
||||
|
@ -131,24 +143,25 @@ fn connect_port(
|
|||
})
|
||||
.into(),
|
||||
);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
match (
|
||||
lhs.canonical_type().type_enum(),
|
||||
rhs.canonical_type().type_enum(),
|
||||
) {
|
||||
(TypeEnum::Deduce(_), _) | (_, TypeEnum::Deduce(_)) => return Err(HitUndeducedType),
|
||||
(TypeEnum::BundleType(lhs_type), TypeEnum::UInt(_)) => {
|
||||
let lhs = lhs.with_type::<DynBundle>();
|
||||
for field in lhs_type.fields() {
|
||||
assert!(!field.flipped);
|
||||
connect_port(stmts, lhs.field(&field.name), rhs, source_location);
|
||||
connect_port(stmts, lhs.field(&field.name), rhs, source_location)?;
|
||||
}
|
||||
}
|
||||
(TypeEnum::UInt(_), TypeEnum::BundleType(rhs_type)) => {
|
||||
let rhs = rhs.with_type::<DynBundle>();
|
||||
for field in rhs_type.fields() {
|
||||
assert!(!field.flipped);
|
||||
connect_port(stmts, lhs, rhs.field(&field.name), source_location);
|
||||
connect_port(stmts, lhs, rhs.field(&field.name), source_location)?;
|
||||
}
|
||||
}
|
||||
(TypeEnum::BundleType(lhs_type), TypeEnum::BundleType(_)) => {
|
||||
|
@ -160,14 +173,14 @@ fn connect_port(
|
|||
} else {
|
||||
(lhs.field(&field.name), rhs.field(&field.name))
|
||||
};
|
||||
connect_port(stmts, lhs_field, rhs_field, source_location);
|
||||
connect_port(stmts, lhs_field, rhs_field, source_location)?;
|
||||
}
|
||||
}
|
||||
(TypeEnum::ArrayType(lhs_type), TypeEnum::ArrayType(_)) => {
|
||||
let lhs = lhs.with_type::<Array<[DynCanonicalValue]>>();
|
||||
let rhs = rhs.with_type::<Array<[DynCanonicalValue]>>();
|
||||
for index in 0..lhs_type.len() {
|
||||
connect_port(stmts, lhs[index], rhs[index], source_location);
|
||||
connect_port(stmts, lhs[index], rhs[index], source_location)?;
|
||||
}
|
||||
}
|
||||
(TypeEnum::BundleType(_), _)
|
||||
|
@ -184,6 +197,7 @@ fn connect_port(
|
|||
rhs.canonical_type().type_enum(),
|
||||
),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Folder for State {
|
||||
|
@ -240,7 +254,7 @@ impl Folder for State {
|
|||
Some(variant_value) => variant_value.fold(self)?.cast_to_bits(),
|
||||
None => DynUInt::with_type(
|
||||
DynUIntType::new(
|
||||
op.ty().bit_width() - op.ty().discriminant_bit_width(),
|
||||
op.ty().bit_width()? - op.ty().discriminant_bit_width(),
|
||||
),
|
||||
0u8,
|
||||
)
|
||||
|
@ -268,7 +282,7 @@ impl Folder for State {
|
|||
.fold(self)?
|
||||
.to_expr()
|
||||
.with_type::<TagAndBody<DynCanonicalValue>>()
|
||||
.body[..op.ty().bit_width()]
|
||||
.body[..op.ty().bit_width()?]
|
||||
.cast_bits_to::<DynCanonicalValue>(op.ty())
|
||||
.expr_enum(),
|
||||
None => ().to_expr().expr_enum(),
|
||||
|
@ -284,7 +298,7 @@ impl Folder for State {
|
|||
.with_type::<DynUInt>();
|
||||
dbg!(base_int);
|
||||
let base_ty = op.base().ty();
|
||||
let ty_bit_width = op.ty().bit_width();
|
||||
let ty_bit_width = op.ty().bit_width()?;
|
||||
base_int[base_ty.discriminant_bit_width()..][..ty_bit_width]
|
||||
.cast_bits_to::<DynCanonicalValue>(op.ty())
|
||||
.expr_enum()
|
||||
|
@ -428,7 +442,7 @@ impl Folder for State {
|
|||
new_port.to_expr().to_canonical_dyn(),
|
||||
wire.to_expr().to_canonical_dyn(),
|
||||
port.source_location(),
|
||||
);
|
||||
)?;
|
||||
self.replacement_mem_ports
|
||||
.insert(port, wire.to_dyn_canonical_wire().intern_sized());
|
||||
}
|
||||
|
@ -562,6 +576,7 @@ impl Folder for State {
|
|||
| TypeEnum::AsyncReset(_)
|
||||
| TypeEnum::SyncReset(_)
|
||||
| TypeEnum::Reset(_) => type_enum.default_fold(self),
|
||||
TypeEnum::Deduce(_) => Err(HitUndeducedType.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -575,7 +590,7 @@ impl Folder for State {
|
|||
}) => ValueEnum::Bundle(
|
||||
TagAndBody {
|
||||
tag: DynEnum::new_by_index(tag_ty, enum_value.variant_index(), None),
|
||||
body: value_to_uint(enum_value.variant_value().as_ref(), body_ty),
|
||||
body: value_to_uint(enum_value.variant_value().as_ref(), body_ty)?,
|
||||
}
|
||||
.to_canonical(),
|
||||
),
|
||||
|
@ -585,12 +600,12 @@ impl Folder for State {
|
|||
}) => ValueEnum::Bundle(
|
||||
TagAndBody {
|
||||
tag: DynUInt::with_type(tag_ty, enum_value.variant_index()),
|
||||
body: value_to_uint(enum_value.variant_value().as_ref(), body_ty),
|
||||
body: value_to_uint(enum_value.variant_value().as_ref(), body_ty)?,
|
||||
}
|
||||
.to_canonical(),
|
||||
),
|
||||
EnumTypeState::UInt(target_ty) => {
|
||||
ValueEnum::UInt(value_to_uint(Some(&enum_value), target_ty))
|
||||
ValueEnum::UInt(value_to_uint(Some(&enum_value), target_ty)?)
|
||||
}
|
||||
EnumTypeState::Unchanged => ValueEnum::Enum(enum_value),
|
||||
})
|
||||
|
|
|
@ -14,13 +14,13 @@ use crate::{
|
|||
},
|
||||
source_location::SourceLocation,
|
||||
ty::{DynCanonicalValue, DynType, Type, TypeEnum},
|
||||
type_deduction::HitUndeducedType,
|
||||
util::MakeMutSlice,
|
||||
wire::Wire,
|
||||
};
|
||||
use bitvec::{slice::BitSlice, vec::BitVec};
|
||||
use hashbrown::HashMap;
|
||||
use std::{
|
||||
convert::Infallible,
|
||||
fmt::Write,
|
||||
ops::{Deref, DerefMut},
|
||||
rc::Rc,
|
||||
|
@ -83,17 +83,17 @@ impl MemSplit {
|
|||
MemSplit::Array { elements: _ } => self,
|
||||
}
|
||||
}
|
||||
fn new(element_type: TypeEnum) -> Self {
|
||||
match element_type {
|
||||
fn new(element_type: TypeEnum) -> Result<Self, HitUndeducedType> {
|
||||
Ok(match element_type {
|
||||
TypeEnum::BundleType(bundle_ty) => MemSplit::Bundle {
|
||||
fields: bundle_ty
|
||||
.fields()
|
||||
.into_iter()
|
||||
.map(|field| Self::new(field.ty.type_enum()).mark_changed_element_type())
|
||||
.collect(),
|
||||
.map(|field| Ok(Self::new(field.ty.type_enum())?.mark_changed_element_type()))
|
||||
.collect::<Result<_, _>>()?,
|
||||
},
|
||||
TypeEnum::ArrayType(ty) => {
|
||||
let element = MemSplit::new(ty.element().type_enum());
|
||||
let element = MemSplit::new(ty.element().type_enum())?;
|
||||
if let Self::Single {
|
||||
output_mem: _,
|
||||
element_type,
|
||||
|
@ -157,14 +157,15 @@ impl MemSplit {
|
|||
},
|
||||
TypeEnum::EnumType(ty) => Self::Single {
|
||||
output_mem: None,
|
||||
element_type: SingleType::UInt(DynUIntType::new(ty.bit_width())),
|
||||
element_type: SingleType::UInt(DynUIntType::new(ty.bit_width()?)),
|
||||
unchanged_element_type: false,
|
||||
},
|
||||
TypeEnum::Clock(_)
|
||||
| TypeEnum::AsyncReset(_)
|
||||
| TypeEnum::SyncReset(_)
|
||||
| TypeEnum::Reset(_) => unreachable!("memory element type is a storable type"),
|
||||
}
|
||||
TypeEnum::Deduce(_) => return Err(HitUndeducedType),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,7 +272,7 @@ struct SplitMemState<'a, 'b> {
|
|||
}
|
||||
|
||||
impl SplitMemState<'_, '_> {
|
||||
fn split_mem(self) {
|
||||
fn split_mem(self) -> Result<(), HitUndeducedType> {
|
||||
let outer_mem_name_path_len = self.mem_name_path.len();
|
||||
match self.split {
|
||||
MemSplit::Bundle { fields } => {
|
||||
|
@ -287,7 +288,7 @@ impl SplitMemState<'_, '_> {
|
|||
self.mem_name_path.truncate(outer_mem_name_path_len);
|
||||
self.mem_name_path.push('_');
|
||||
self.mem_name_path.push_str(&field.name);
|
||||
let field_ty_bit_width = field.ty.bit_width();
|
||||
let field_ty_bit_width = field.ty.bit_width()?;
|
||||
self.split_state_stack.push_map(
|
||||
|e: Expr<DynCanonicalValue>| e.with_type::<DynBundle>().field(&field.name),
|
||||
|initial_value_element| {
|
||||
|
@ -305,7 +306,7 @@ impl SplitMemState<'_, '_> {
|
|||
split_state_stack: self.split_state_stack,
|
||||
mem_state: self.mem_state,
|
||||
}
|
||||
.split_mem();
|
||||
.split_mem()?;
|
||||
self.split_state_stack.pop();
|
||||
}
|
||||
}
|
||||
|
@ -321,7 +322,7 @@ impl SplitMemState<'_, '_> {
|
|||
*single_type,
|
||||
self.mem_name_path,
|
||||
self.split_state_stack.top(),
|
||||
);
|
||||
)?;
|
||||
for (port, wire) in new_mem
|
||||
.ports()
|
||||
.into_iter()
|
||||
|
@ -356,7 +357,7 @@ impl SplitMemState<'_, '_> {
|
|||
unreachable!();
|
||||
};
|
||||
let element_type = array_type.element().type_enum();
|
||||
let element_bit_width = array_type.element().bit_width();
|
||||
let element_bit_width = array_type.element().bit_width()?;
|
||||
for (index, split) in elements.make_mut_slice().iter_mut().enumerate() {
|
||||
self.mem_name_path.truncate(outer_mem_name_path_len);
|
||||
write!(self.mem_name_path, "_{index}").unwrap();
|
||||
|
@ -379,11 +380,12 @@ impl SplitMemState<'_, '_> {
|
|||
split_state_stack: self.split_state_stack,
|
||||
mem_state: self.mem_state,
|
||||
}
|
||||
.split_mem();
|
||||
.split_mem()?;
|
||||
self.split_state_stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -465,7 +467,7 @@ impl ModuleState {
|
|||
port_rdata: Option<Expr<DynCanonicalValue>>,
|
||||
port_wdata: Option<Expr<DynCanonicalValue>>,
|
||||
port_wmask: Option<Expr<DynCanonicalValue>>,
|
||||
) {
|
||||
) -> Result<(), HitUndeducedType> {
|
||||
let mut input_array_types = vec![];
|
||||
let connect_read = |output_stmts: &mut Vec<Stmt>,
|
||||
wire_read: Expr<DynCanonicalValue>,
|
||||
|
@ -599,9 +601,11 @@ impl ModuleState {
|
|||
| TypeEnum::AsyncReset(_)
|
||||
| TypeEnum::SyncReset(_)
|
||||
| TypeEnum::Reset(_) => unreachable!("memory element type is a storable type"),
|
||||
TypeEnum::Deduce(_) => return Err(HitUndeducedType),
|
||||
}
|
||||
break;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn create_split_mem(
|
||||
&mut self,
|
||||
|
@ -611,7 +615,7 @@ impl ModuleState {
|
|||
single_type: SingleType,
|
||||
mem_name_path: &str,
|
||||
split_state: &SplitState<'_>,
|
||||
) -> Mem<[DynCanonicalValue]> {
|
||||
) -> Result<Mem<[DynCanonicalValue]>, HitUndeducedType> {
|
||||
let mem_name = self.name_id_gen.gen(Intern::intern_owned(format!(
|
||||
"{}{mem_name_path}",
|
||||
input_mem.scoped_name().1 .0
|
||||
|
@ -625,8 +629,9 @@ impl ModuleState {
|
|||
};
|
||||
let output_array_type =
|
||||
ArrayType::new_slice(output_element_type, input_mem.array_type().len());
|
||||
let output_array_bit_width = output_array_type.bit_width()?;
|
||||
let initial_value = split_state.initial_value.as_ref().map(|initial_value| {
|
||||
let mut bits = BitVec::with_capacity(output_array_type.bit_width());
|
||||
let mut bits = BitVec::with_capacity(output_array_bit_width);
|
||||
for element in initial_value.iter() {
|
||||
bits.extend_from_bitslice(element);
|
||||
}
|
||||
|
@ -696,18 +701,18 @@ impl ModuleState {
|
|||
port_rdata,
|
||||
port_wdata,
|
||||
port_wmask,
|
||||
);
|
||||
)?;
|
||||
}
|
||||
output_mem
|
||||
Ok(output_mem)
|
||||
}
|
||||
fn process_mem(
|
||||
&mut self,
|
||||
input_mem: Mem<[DynCanonicalValue]>,
|
||||
output_mems: &mut Vec<Mem<[DynCanonicalValue]>>,
|
||||
output_stmts: &mut Vec<Stmt>,
|
||||
) {
|
||||
) -> Result<(), HitUndeducedType> {
|
||||
let element_type = input_mem.array_type().element().type_enum();
|
||||
let mut split = MemSplit::new(element_type);
|
||||
let mut split = MemSplit::new(element_type)?;
|
||||
let mem_state = match split {
|
||||
MemSplit::Single {
|
||||
ref mut output_mem,
|
||||
|
@ -805,11 +810,12 @@ impl ModuleState {
|
|||
),
|
||||
mem_state: &mem_state,
|
||||
}
|
||||
.split_mem();
|
||||
.split_mem()?;
|
||||
mem_state
|
||||
}
|
||||
};
|
||||
self.memories.insert(input_mem.scoped_name(), mem_state);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -858,7 +864,7 @@ impl DerefMut for PushedState<'_> {
|
|||
}
|
||||
|
||||
impl Folder for State {
|
||||
type Error = Infallible;
|
||||
type Error = HitUndeducedType;
|
||||
|
||||
fn fold_module<T: BundleValue>(&mut self, v: Module<T>) -> Result<Module<T>, Self::Error>
|
||||
where
|
||||
|
@ -902,13 +908,11 @@ impl Folder for State {
|
|||
let mut output_stmts = vec![];
|
||||
let module_state = self.module_state();
|
||||
for input_mem in input_mems {
|
||||
module_state.process_mem(input_mem, &mut output_mems, &mut output_stmts);
|
||||
module_state.process_mem(input_mem, &mut output_mems, &mut output_stmts)?;
|
||||
}
|
||||
for stmt in input_stmts {
|
||||
output_stmts.push(stmt.fold(self)?);
|
||||
}
|
||||
output_stmts.extend(
|
||||
input_stmts
|
||||
.into_iter()
|
||||
.map(|stmt| stmt.fold(self).unwrap_or_else(|v| match v {})),
|
||||
);
|
||||
Ok(Block {
|
||||
memories: Intern::intern_owned(output_mems),
|
||||
stmts: Intern::intern_owned(output_stmts),
|
||||
|
@ -933,8 +937,8 @@ impl Folder for State {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn simplify_memories(module: Interned<Module<DynBundle>>) -> Interned<Module<DynBundle>> {
|
||||
module
|
||||
.fold(&mut State::default())
|
||||
.unwrap_or_else(|v| match v {})
|
||||
pub fn simplify_memories(
|
||||
module: Interned<Module<DynBundle>>,
|
||||
) -> Result<Interned<Module<DynBundle>>, HitUndeducedType> {
|
||||
module.fold(&mut State::default())
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ use crate::{
|
|||
TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, ToExpr,
|
||||
},
|
||||
int::{
|
||||
DynInt, DynIntType, DynSInt, DynSIntType, DynUInt, DynUIntType, StaticOrDynIntType, IntType,
|
||||
IntTypeTrait,
|
||||
DynInt, DynIntType, DynSInt, DynSIntType, DynUInt, DynUIntType, IntType, IntTypeTrait,
|
||||
StaticOrDynIntType,
|
||||
},
|
||||
intern::{Intern, Interned},
|
||||
memory::{Mem, MemPort, PortKind, PortName, PortType, ReadUnderWrite},
|
||||
|
@ -27,6 +27,7 @@ use crate::{
|
|||
reset::{AsyncReset, AsyncResetType, Reset, ResetType, SyncReset, SyncResetType},
|
||||
source_location::SourceLocation,
|
||||
ty::{DynCanonicalType, DynCanonicalValue, DynType, Type, TypeEnum, Value, ValueEnum},
|
||||
type_deduction::UndeducedType,
|
||||
util::{ConstBool, GenericConstBool},
|
||||
wire::Wire,
|
||||
};
|
||||
|
|
|
@ -106,7 +106,10 @@ impl<T: Type> Reg<T> {
|
|||
clock_domain: Expr<ClockDomain>,
|
||||
init: Option<Expr<T::Value>>,
|
||||
) -> Self {
|
||||
assert!(ty.is_storable(), "register type must be a storable type");
|
||||
assert!(
|
||||
ty.is_storable().unwrap_or(true),
|
||||
"register type must be a storable type"
|
||||
);
|
||||
if let Some(init) = init {
|
||||
assert_eq!(ty, init.ty(), "register's type must match init type");
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use crate::{
|
|||
impl_match_values_as_self, CanonicalType, CanonicalTypeKind, CanonicalValue, Connect,
|
||||
DynCanonicalType, StaticType, Type, TypeEnum, Value, ValueEnum,
|
||||
},
|
||||
type_deduction::{HitUndeducedType, UndeducedType},
|
||||
util::interned_bit,
|
||||
};
|
||||
use bitvec::slice::BitSlice;
|
||||
|
@ -24,6 +25,8 @@ impl AsyncResetType {
|
|||
}
|
||||
}
|
||||
|
||||
impl Connect<UndeducedType> for AsyncResetType {}
|
||||
|
||||
impl Type for AsyncResetType {
|
||||
type Value = AsyncReset;
|
||||
type CanonicalType = AsyncResetType;
|
||||
|
@ -91,8 +94,8 @@ impl Value for AsyncReset {
|
|||
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
|
||||
*self
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
interned_bit(this.0)
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
Ok(interned_bit(this.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,8 +103,8 @@ impl CanonicalValue for AsyncReset {
|
|||
fn value_enum_impl(this: &Self) -> ValueEnum {
|
||||
ValueEnum::AsyncReset(*this)
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
interned_bit(this.0)
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
Ok(interned_bit(this.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,6 +117,8 @@ impl SyncResetType {
|
|||
}
|
||||
}
|
||||
|
||||
impl Connect<UndeducedType> for SyncResetType {}
|
||||
|
||||
impl Type for SyncResetType {
|
||||
type CanonicalType = SyncResetType;
|
||||
type Value = SyncReset;
|
||||
|
@ -181,8 +186,8 @@ impl Value for SyncReset {
|
|||
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
|
||||
*self
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
interned_bit(this.0)
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
Ok(interned_bit(this.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,8 +195,8 @@ impl CanonicalValue for SyncReset {
|
|||
fn value_enum_impl(this: &Self) -> ValueEnum {
|
||||
ValueEnum::SyncReset(*this)
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
interned_bit(this.0)
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
Ok(interned_bit(this.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,6 +209,8 @@ impl ResetType {
|
|||
}
|
||||
}
|
||||
|
||||
impl Connect<UndeducedType> for ResetType {}
|
||||
|
||||
impl Type for ResetType {
|
||||
type Value = Reset;
|
||||
type CanonicalType = ResetType;
|
||||
|
@ -271,7 +278,7 @@ impl Value for Reset {
|
|||
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
|
||||
*self
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
match *this {}
|
||||
}
|
||||
}
|
||||
|
@ -280,7 +287,7 @@ impl CanonicalValue for Reset {
|
|||
fn value_enum_impl(this: &Self) -> ValueEnum {
|
||||
ValueEnum::Reset(*this)
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
match *this {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use crate::{
|
|||
},
|
||||
reset::{AsyncReset, AsyncResetType, Reset, ResetType, SyncReset, SyncResetType},
|
||||
source_location::SourceLocation,
|
||||
type_deduction::{Deduce, HitUndeducedType, UndeducedType},
|
||||
util::{iter_eq_by, GenericConstBool},
|
||||
valueless::Valueless,
|
||||
};
|
||||
|
@ -46,6 +47,7 @@ pub enum TypeEnum {
|
|||
AsyncReset(AsyncResetType),
|
||||
SyncReset(SyncResetType),
|
||||
Reset(ResetType),
|
||||
Deduce(UndeducedType),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
|
@ -60,6 +62,7 @@ pub enum CanonicalTypeKind {
|
|||
SyncReset,
|
||||
Reset,
|
||||
DynCanonicalType,
|
||||
Deduce,
|
||||
}
|
||||
|
||||
impl CanonicalTypeKind {
|
||||
|
@ -75,6 +78,7 @@ impl CanonicalTypeKind {
|
|||
CanonicalTypeKind::SyncReset => "Expr<SyncReset>",
|
||||
CanonicalTypeKind::Reset => "Expr<Reset>",
|
||||
CanonicalTypeKind::DynCanonicalType => "Expr<DynCanonicalValue>",
|
||||
CanonicalTypeKind::Deduce => "Expr<Deduce>",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,57 +97,61 @@ pub enum ValueEnum {
|
|||
}
|
||||
|
||||
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(),
|
||||
pub fn is_passive(self) -> Result<bool, HitUndeducedType> {
|
||||
Ok(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,
|
||||
}
|
||||
TypeEnum::Deduce(_) => return Err(HitUndeducedType),
|
||||
})
|
||||
}
|
||||
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(),
|
||||
pub fn is_storable(self) -> Result<bool, HitUndeducedType> {
|
||||
Ok(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,
|
||||
}
|
||||
TypeEnum::Deduce(_) => return Err(HitUndeducedType),
|
||||
})
|
||||
}
|
||||
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(),
|
||||
pub fn is_castable_from_bits(self) -> Result<bool, HitUndeducedType> {
|
||||
Ok(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
|
||||
}
|
||||
TypeEnum::Deduce(_) => return Err(HitUndeducedType),
|
||||
})
|
||||
}
|
||||
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),
|
||||
pub fn bit_width(self) -> Result<usize, HitUndeducedType> {
|
||||
Ok(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,
|
||||
}
|
||||
TypeEnum::Deduce(_) => return Err(HitUndeducedType),
|
||||
})
|
||||
}
|
||||
pub fn bundle_type(self) -> Option<DynBundleType> {
|
||||
if let TypeEnum::BundleType(retval) = self {
|
||||
|
@ -208,6 +216,13 @@ impl TypeEnum {
|
|||
None
|
||||
}
|
||||
}
|
||||
pub fn undeduced(self) -> Option<UndeducedType> {
|
||||
if let TypeEnum::Deduce(retval) = self {
|
||||
Some(retval)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn to_dyn(self) -> Interned<dyn DynType> {
|
||||
match self {
|
||||
TypeEnum::BundleType(ty) => ty.to_dyn(),
|
||||
|
@ -219,6 +234,7 @@ impl TypeEnum {
|
|||
TypeEnum::AsyncReset(ty) => ty.to_dyn(),
|
||||
TypeEnum::SyncReset(ty) => ty.to_dyn(),
|
||||
TypeEnum::Reset(ty) => ty.to_dyn(),
|
||||
TypeEnum::Deduce(ty) => ty.to_dyn(),
|
||||
}
|
||||
}
|
||||
pub fn canonical_dyn(self) -> Interned<dyn DynCanonicalType> {
|
||||
|
@ -232,6 +248,7 @@ impl TypeEnum {
|
|||
TypeEnum::AsyncReset(ty) => ty.canonical_dyn(),
|
||||
TypeEnum::SyncReset(ty) => ty.canonical_dyn(),
|
||||
TypeEnum::Reset(ty) => ty.canonical_dyn(),
|
||||
TypeEnum::Deduce(ty) => ty.canonical_dyn(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -242,10 +259,10 @@ pub trait DynType: fmt::Debug + Send + Sync + Any + SupportsPtrEqWithTypeId {
|
|||
fn mask_type_dyn(&self) -> Interned<dyn DynType>;
|
||||
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 is_passive(&self) -> Result<bool, HitUndeducedType>;
|
||||
fn is_storable(&self) -> Result<bool, HitUndeducedType>;
|
||||
fn is_castable_from_bits(&self) -> Result<bool, HitUndeducedType>;
|
||||
fn bit_width(&self) -> Result<usize, HitUndeducedType>;
|
||||
fn as_dyn_type(&self) -> &dyn DynType;
|
||||
fn as_dyn_canonical_type(&self) -> Option<&dyn DynCanonicalType>;
|
||||
#[deprecated = "use <dyn DynType>::downcast or <dyn DynCanonicalType>::downcast instead, they properly handle Interned<dyn DynType> and Interned<dyn DynCanonicalType>"]
|
||||
|
@ -294,19 +311,19 @@ impl<T: Type> DynType for T {
|
|||
self.type_enum()
|
||||
}
|
||||
|
||||
fn is_passive(&self) -> bool {
|
||||
fn is_passive(&self) -> Result<bool, HitUndeducedType> {
|
||||
self.type_enum().is_passive()
|
||||
}
|
||||
|
||||
fn is_storable(&self) -> bool {
|
||||
fn is_storable(&self) -> Result<bool, HitUndeducedType> {
|
||||
self.type_enum().is_storable()
|
||||
}
|
||||
|
||||
fn is_castable_from_bits(&self) -> bool {
|
||||
fn is_castable_from_bits(&self) -> Result<bool, HitUndeducedType> {
|
||||
self.type_enum().is_castable_from_bits()
|
||||
}
|
||||
|
||||
fn bit_width(&self) -> usize {
|
||||
fn bit_width(&self) -> Result<usize, HitUndeducedType> {
|
||||
self.type_enum().bit_width()
|
||||
}
|
||||
|
||||
|
@ -459,7 +476,9 @@ impl<T: 'static + Send + Sync> MatchVariantAndInactiveScope for MatchVariantWith
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Type: DynType + Clone + Hash + Eq + Intern + Connect<Self> {
|
||||
pub trait Type:
|
||||
DynType + Clone + Hash + Eq + Intern + Connect<Self> + Connect<UndeducedType>
|
||||
{
|
||||
type CanonicalType: CanonicalType<
|
||||
CanonicalType = Self::CanonicalType,
|
||||
CanonicalValue = Self::CanonicalValue,
|
||||
|
@ -562,8 +581,9 @@ pub trait CanonicalType:
|
|||
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;
|
||||
let other_ty = other.type_enum();
|
||||
let Some($var) = other_ty.$fn() else {
|
||||
return other_ty.undeduced().is_some();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -619,6 +639,7 @@ pub trait CanonicalType:
|
|||
unwrap_other!(other = reset());
|
||||
this == other
|
||||
}
|
||||
TypeEnum::Deduce(_) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -641,7 +662,7 @@ pub trait DynValueTrait: fmt::Debug + Send + Sync + Any {
|
|||
fn as_any(&self) -> &(dyn Any + Send + Sync);
|
||||
fn as_dyn_value_trait(&self) -> &dyn DynValueTrait;
|
||||
fn as_arc_dyn_value_trait(self: Arc<Self>) -> Arc<dyn DynValueTrait>;
|
||||
fn to_bits(&self) -> Interned<BitSlice>;
|
||||
fn to_bits(&self) -> Result<Interned<BitSlice>, HitUndeducedType>;
|
||||
}
|
||||
|
||||
macro_rules! dyn_value {
|
||||
|
@ -707,7 +728,7 @@ impl Value for DynValue {
|
|||
self.0.to_canonical_dyn()
|
||||
}
|
||||
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
this.0.to_bits()
|
||||
}
|
||||
}
|
||||
|
@ -743,7 +764,7 @@ impl Value for DynCanonicalValue {
|
|||
self.0.to_canonical_dyn()
|
||||
}
|
||||
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
<Self as CanonicalValue>::to_bits_impl(this)
|
||||
}
|
||||
}
|
||||
|
@ -759,7 +780,7 @@ impl CanonicalValue for DynCanonicalValue {
|
|||
this.0.value_enum()
|
||||
}
|
||||
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
this.0.to_bits()
|
||||
}
|
||||
}
|
||||
|
@ -807,7 +828,7 @@ pub trait Value: DynValueTrait + Clone + Eq + Hash + ToExpr {
|
|||
fn valueless(&self) -> Valueless<Self::Type> {
|
||||
Valueless { ty: self.ty() }
|
||||
}
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
<<Self::Type as Type>::CanonicalValue as CanonicalValue>::to_bits_impl(&this.to_canonical())
|
||||
}
|
||||
}
|
||||
|
@ -844,7 +865,7 @@ where
|
|||
)
|
||||
}
|
||||
fn value_enum_impl(this: &Self) -> ValueEnum;
|
||||
fn to_bits_impl(this: &Self) -> Interned<BitSlice>;
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType>;
|
||||
}
|
||||
|
||||
impl<T: Value> DynValueTrait for T
|
||||
|
@ -884,11 +905,13 @@ where
|
|||
self
|
||||
}
|
||||
|
||||
fn to_bits(&self) -> Interned<BitSlice> {
|
||||
fn to_bits(&self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
T::to_bits_impl(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Connect<UndeducedType> for Interned<dyn DynType> {}
|
||||
|
||||
impl Type for Interned<dyn DynType> {
|
||||
type CanonicalType = Interned<dyn DynCanonicalType>;
|
||||
type Value = DynValue;
|
||||
|
@ -977,6 +1000,8 @@ impl Type for Interned<dyn DynCanonicalType> {
|
|||
|
||||
impl Connect<Self> for Interned<dyn DynCanonicalType> {}
|
||||
|
||||
impl Connect<UndeducedType> for Interned<dyn DynCanonicalType> {}
|
||||
|
||||
impl sealed::Sealed for Interned<dyn DynCanonicalType> {}
|
||||
|
||||
impl CanonicalType for Interned<dyn DynCanonicalType> {
|
||||
|
@ -1014,3 +1039,7 @@ impl sealed::Sealed for Array<[DynCanonicalValue]> {}
|
|||
impl sealed::Sealed for DynEnumType {}
|
||||
|
||||
impl sealed::Sealed for DynEnum {}
|
||||
|
||||
impl sealed::Sealed for UndeducedType {}
|
||||
|
||||
impl sealed::Sealed for Deduce {}
|
||||
|
|
136
crates/fayalite/src/type_deduction.rs
Normal file
136
crates/fayalite/src/type_deduction.rs
Normal file
|
@ -0,0 +1,136 @@
|
|||
use crate::{
|
||||
expr::{Expr, ToExpr},
|
||||
intern::Interned,
|
||||
source_location::SourceLocation,
|
||||
ty::{
|
||||
impl_match_values_as_self, CanonicalType, CanonicalTypeKind, CanonicalValue, Connect, Type,
|
||||
TypeEnum, Value, ValueEnum,
|
||||
},
|
||||
};
|
||||
use bitvec::prelude::BitSlice;
|
||||
use std::{
|
||||
fmt,
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[non_exhaustive]
|
||||
pub struct HitUndeducedType;
|
||||
|
||||
impl HitUndeducedType {
|
||||
/// if either input is [`Ok(false)`][Ok], return [`Ok(false)`][Ok],
|
||||
/// otherwise if either input is [`Err(_)`][Err], return [`Err(_)`][Err],
|
||||
/// otherwise return [`Ok(true)`][Ok].
|
||||
pub fn reduce_and(l: Result<bool, Self>, r: Result<bool, Self>) -> Result<bool, Self> {
|
||||
match (l, r) {
|
||||
(Ok(false), _) | (_, Ok(false)) => Ok(false),
|
||||
(Err(e), _) | (_, Err(e)) => Err(e),
|
||||
(Ok(true), Ok(true)) => Ok(true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for HitUndeducedType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("encountered a not-yet-deduced type")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for HitUndeducedType {}
|
||||
|
||||
#[derive(Copy, Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct UndeducedType {
|
||||
id: u64,
|
||||
mask_ty_id: u64,
|
||||
source_location: SourceLocation,
|
||||
}
|
||||
|
||||
impl UndeducedType {
|
||||
#[track_caller]
|
||||
pub fn new() -> Self {
|
||||
Self::new_with_loc(SourceLocation::caller())
|
||||
}
|
||||
pub fn new_with_loc(source_location: SourceLocation) -> Self {
|
||||
static NEXT_ID: AtomicU64 = AtomicU64::new(0);
|
||||
let id = NEXT_ID.fetch_add(2, Ordering::Relaxed);
|
||||
let mask_ty_id = id + 1;
|
||||
Self {
|
||||
id,
|
||||
mask_ty_id,
|
||||
source_location,
|
||||
}
|
||||
}
|
||||
pub fn id(self) -> u64 {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Connect<T> for UndeducedType {}
|
||||
|
||||
impl Type for UndeducedType {
|
||||
type CanonicalType = UndeducedType;
|
||||
type Value = Deduce;
|
||||
type CanonicalValue = Deduce;
|
||||
type MaskType = UndeducedType;
|
||||
type MaskValue = Deduce;
|
||||
impl_match_values_as_self!();
|
||||
|
||||
fn mask_type(&self) -> Self::MaskType {
|
||||
Self {
|
||||
id: self.mask_ty_id,
|
||||
mask_ty_id: self.mask_ty_id,
|
||||
source_location: self.source_location,
|
||||
}
|
||||
}
|
||||
|
||||
fn canonical(&self) -> Self::CanonicalType {
|
||||
*self
|
||||
}
|
||||
|
||||
fn source_location(&self) -> SourceLocation {
|
||||
self.source_location
|
||||
}
|
||||
|
||||
fn type_enum(&self) -> TypeEnum {
|
||||
TypeEnum::Deduce(*self)
|
||||
}
|
||||
|
||||
fn from_canonical_type(t: Self::CanonicalType) -> Self {
|
||||
t
|
||||
}
|
||||
}
|
||||
|
||||
impl CanonicalType for UndeducedType {
|
||||
const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::Deduce;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum Deduce {}
|
||||
|
||||
impl ToExpr for Deduce {
|
||||
type Type = UndeducedType;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
match *self {}
|
||||
}
|
||||
|
||||
fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
|
||||
match *self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Value for Deduce {
|
||||
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl CanonicalValue for Deduce {
|
||||
fn value_enum_impl(this: &Self) -> ValueEnum {
|
||||
match *this {}
|
||||
}
|
||||
|
||||
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
|
||||
match *this {}
|
||||
}
|
||||
}
|
|
@ -57,7 +57,8 @@
|
|||
"Clock": "Visible",
|
||||
"AsyncReset": "Visible",
|
||||
"SyncReset": "Visible",
|
||||
"Reset": "Visible"
|
||||
"Reset": "Visible",
|
||||
"Deduce": "Visible"
|
||||
}
|
||||
},
|
||||
"DynBundleType": {
|
||||
|
@ -120,6 +121,11 @@
|
|||
"$kind": "Struct"
|
||||
}
|
||||
},
|
||||
"UndeducedType": {
|
||||
"data": {
|
||||
"$kind": "Opaque"
|
||||
}
|
||||
},
|
||||
"AsyncResetType": {
|
||||
"data": {
|
||||
"$kind": "Struct"
|
||||
|
|
Loading…
Reference in a new issue