Compare commits

..

No commits in common. "type-deduction" and "master" have entirely different histories.

21 changed files with 427 additions and 855 deletions

View file

@ -815,12 +815,6 @@ 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

View file

@ -522,12 +522,6 @@ 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

View file

@ -17,7 +17,6 @@ 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};
@ -196,7 +195,7 @@ where
pub struct ArrayType<VA: ValueArrayOrSlice + ?Sized> {
element: VA::ElementType,
len: VA::LenType,
bit_width: Result<usize, HitUndeducedType>,
bit_width: usize,
}
pub trait ArrayTypeTrait:
@ -211,6 +210,7 @@ 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,8 +220,6 @@ 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;
@ -250,7 +248,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> ArrayType<VA> {
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn bit_width(&self) -> Result<usize, HitUndeducedType> {
pub fn bit_width(&self) -> usize {
self.bit_width
}
pub fn into_slice_type(self) -> ArrayType<[VA::Element]> {
@ -268,18 +266,10 @@ impl<VA: ValueArrayOrSlice + ?Sized> ArrayType<VA> {
)
}
#[track_caller]
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 {
pub fn new_with_len_type(element: VA::ElementType, len: VA::LenType) -> Self {
let Some(bit_width) = VA::len_from_len_type(len).checked_mul(element.bit_width()) else {
panic!("array is too big: bit-width overflowed");
};
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,
@ -447,7 +437,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> Value for Array<VA> {
.collect(),
}
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
#[derive(Hash, Eq, PartialEq)]
struct ArrayToBitsMemoize<VA: ValueArrayOrSlice + ?Sized>(PhantomData<VA>);
impl<VA: ValueArrayOrSlice + ?Sized> Clone for ArrayToBitsMemoize<VA> {
@ -459,14 +449,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 = Result<Interned<BitSlice>, HitUndeducedType>;
type Output = Interned<BitSlice>;
fn inner(self, input: &Self::Input) -> Self::Output {
let mut bits = BitVec::with_capacity(input.ty().bit_width().unwrap_or(0));
let mut bits = BitVec::with_capacity(input.ty().bit_width());
for element in AsRef::<[_]>::as_ref(&*input.value).iter() {
bits.extend_from_bitslice(&element.to_bits()?);
bits.extend_from_bitslice(&element.to_bits());
}
Ok(Intern::intern_owned(bits))
Intern::intern_owned(bits)
}
}
ArrayToBitsMemoize::<VA>(PhantomData).get(this)
@ -477,7 +467,7 @@ impl CanonicalValue for Array<[DynCanonicalValue]> {
fn value_enum_impl(this: &Self) -> ValueEnum {
ValueEnum::Array(this.clone())
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
Value::to_bits_impl(this)
}
}

View file

@ -12,7 +12,6 @@ use crate::{
DynCanonicalValue, DynType, MatchVariantWithoutScope, StaticType, Type, TypeEnum,
TypeWithDeref, Value, ValueEnum,
},
type_deduction::{HitUndeducedType, UndeducedType},
};
use bitvec::{slice::BitSlice, vec::BitVec};
use hashbrown::HashMap;
@ -32,7 +31,7 @@ pub struct FieldType<T> {
pub struct FmtDebugInStruct<'a, T> {
field: &'a FieldType<T>,
field_offset: Option<usize>,
field_offset: usize,
}
impl<T: fmt::Debug> fmt::Debug for FmtDebugInStruct<'_, T> {
@ -50,9 +49,7 @@ impl<T: fmt::Debug> fmt::Debug for FmtDebugInStruct<'_, T> {
write!(f, "#[hdl(flip)] ")?;
}
if f.alternate() {
if let Some(field_offset) = field_offset {
writeln!(f, "/* offset = {field_offset} */")?;
}
writeln!(f, "/* offset = {field_offset} */")?;
}
write!(f, "{name}: ")?;
ty.fmt(f)
@ -81,7 +78,7 @@ impl<T> FieldType<T> {
ty: &self.ty,
}
}
pub fn fmt_debug_in_struct(&self, field_offset: Option<usize>) -> FmtDebugInStruct<'_, T> {
pub fn fmt_debug_in_struct(&self, field_offset: usize) -> FmtDebugInStruct<'_, T> {
FmtDebugInStruct {
field: self,
field_offset,
@ -138,19 +135,22 @@ struct DynBundleTypeImpl {
fields: Interned<[FieldType<Interned<dyn DynCanonicalType>>]>,
name_indexes: HashMap<Interned<str>, usize>,
field_offsets: Interned<[usize]>,
is_passive: Result<bool, HitUndeducedType>,
is_storable: Result<bool, HitUndeducedType>,
is_castable_from_bits: Result<bool, HitUndeducedType>,
bit_width: Result<usize, HitUndeducedType>,
is_passive: bool,
is_storable: bool,
is_castable_from_bits: bool,
bit_width: usize,
}
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.get(index).copied())
}))
.entries(
self.fields
.iter()
.enumerate()
.map(|(index, field)| field.fmt_debug_in_struct(self.field_offsets[index])),
)
.finish()
}
}
@ -178,39 +178,26 @@ impl fmt::Debug for DynBundleType {
impl DynBundleType {
pub fn new(fields: Interned<[FieldType<Interned<dyn DynCanonicalType>>]>) -> Self {
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 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());
let mut name_indexes = HashMap::with_capacity(fields.len());
let mut field_offsets = Vec::with_capacity(fields.len());
let mut bit_width = Ok(0usize);
let mut bit_width = 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}");
}
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"))
});
}
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"));
}
Self(
DynBundleTypeImpl {
@ -225,16 +212,16 @@ impl DynBundleType {
.intern_sized(),
)
}
pub fn is_passive(self) -> Result<bool, HitUndeducedType> {
pub fn is_passive(self) -> bool {
self.0.is_passive
}
pub fn is_storable(self) -> Result<bool, HitUndeducedType> {
pub fn is_storable(self) -> bool {
self.0.is_storable
}
pub fn is_castable_from_bits(self) -> Result<bool, HitUndeducedType> {
pub fn is_castable_from_bits(self) -> bool {
self.0.is_castable_from_bits
}
pub fn bit_width(self) -> Result<usize, HitUndeducedType> {
pub fn bit_width(self) -> usize {
self.0.bit_width
}
pub fn name_indexes(&self) -> &HashMap<Interned<str>, usize> {
@ -383,7 +370,7 @@ impl FieldsHint {
}
pub trait BundleType:
Type<CanonicalType = DynBundleType, CanonicalValue = DynBundle> + TypeWithDeref
Type<CanonicalType = DynBundleType, CanonicalValue = DynBundle> + TypeWithDeref + Connect<Self>
where
Self::Value: BundleValue + ToExpr<Type = Self>,
{
@ -397,7 +384,7 @@ pub trait BundleValue: Value
where
<Self as ToExpr>::Type: BundleType<Value = Self>,
{
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
#[derive(Hash, Eq, PartialEq)]
struct ToBitsMemoize<T>(PhantomData<T>);
impl<T> Clone for ToBitsMemoize<T> {
@ -409,23 +396,21 @@ where
impl<T: BundleValue<Type: BundleType<Value = T>>> Memoize for ToBitsMemoize<T> {
type Input = T;
type InputOwned = T;
type Output = Result<Interned<BitSlice>, HitUndeducedType>;
type Output = Interned<BitSlice>;
fn inner(self, input: &Self::Input) -> Self::Output {
let input = input.to_canonical();
let mut bits = BitVec::with_capacity(input.ty.bit_width().unwrap_or(0));
let mut bits = BitVec::with_capacity(input.ty.bit_width());
for field in input.fields.iter() {
bits.extend_from_bitslice(&field.to_bits()?);
bits.extend_from_bitslice(&field.to_bits());
}
Ok(Intern::intern_owned(bits))
Intern::intern_owned(bits)
}
}
ToBitsMemoize::<Self>(PhantomData).get(this)
}
}
impl Connect<UndeducedType> for DynBundleType {}
pub struct DynBundleMatch;
impl Type for DynBundleType {
@ -549,7 +534,7 @@ impl Value for DynBundle {
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
self.clone()
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
BundleValue::to_bits_impl(this)
}
}
@ -560,7 +545,7 @@ impl CanonicalValue for DynBundle {
fn value_enum_impl(this: &Self) -> ValueEnum {
ValueEnum::Bundle(this.clone())
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
BundleValue::to_bits_impl(this)
}
}
@ -660,8 +645,6 @@ macro_rules! impl_tuple {
}
}
impl<$($T,)*> Connect<UndeducedType> for ($($T,)*) {}
impl<$($T, $T2,)*> Connect<($($T2,)*)> for ($($T,)*)
where
$($T: Connect<$T2>,)*
@ -795,7 +778,7 @@ macro_rules! impl_tuple {
]),
)
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
BundleValue::to_bits_impl(this)
}
}

View file

@ -10,7 +10,6 @@ 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,8 +23,6 @@ impl ClockType {
}
}
impl Connect<UndeducedType> for ClockType {}
impl Type for ClockType {
type Value = Clock;
type CanonicalType = ClockType;
@ -91,8 +88,8 @@ impl Value for Clock {
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
*self
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
Ok(interned_bit(this.0))
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
interned_bit(this.0)
}
}
@ -100,8 +97,8 @@ impl CanonicalValue for Clock {
fn value_enum_impl(this: &Self) -> ValueEnum {
ValueEnum::Clock(*this)
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
Ok(interned_bit(this.0))
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
interned_bit(this.0)
}
}

View file

@ -3,7 +3,7 @@
#![allow(clippy::type_complexity)]
use crate::{
bundle::{BundleValue, TypeHintTrait},
expr::{ops::VariantAccess, Expr, NotALiteralExpr, ToExpr},
expr::{ops::VariantAccess, Expr, ToExpr},
int::{UInt, UIntType},
intern::{Intern, Interned, MemoizeGeneric},
module::{
@ -15,7 +15,6 @@ 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;
@ -108,9 +107,9 @@ impl VariantType<Interned<dyn DynCanonicalType>> {
struct DynEnumTypeImpl {
variants: Interned<[VariantType<Interned<dyn DynCanonicalType>>]>,
name_indexes: HashMap<Interned<str>, usize>,
bit_width: Result<usize, HitUndeducedType>,
is_storable: Result<bool, HitUndeducedType>,
is_castable_from_bits: Result<bool, HitUndeducedType>,
bit_width: usize,
is_storable: bool,
is_castable_from_bits: bool,
}
impl fmt::Debug for DynEnumTypeImpl {
@ -159,28 +158,26 @@ 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 = Ok(0usize);
let mut is_storable = Ok(true);
let mut is_castable_from_bits = Ok(true);
let mut body_bit_width = 0usize;
let mut is_storable = true;
let mut is_castable_from_bits = true;
for (index, &VariantType { name, ty }) in variants.iter().enumerate() {
if let Some(old_index) = name_indexes.insert(name, index) {
panic!("duplicate variant name {name:?}: at both index {old_index} and {index}");
}
if let Some(ty) = ty {
assert!(
ty.is_passive().unwrap_or(true),
ty.is_passive(),
"variant type must be a passive type: {ty:?}"
);
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());
body_bit_width = body_bit_width.max(ty.bit_width());
is_storable &= ty.is_storable();
is_castable_from_bits &= ty.is_castable_from_bits();
}
}
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"))
});
let bit_width = body_bit_width
.checked_add(discriminant_bit_width_impl(variants.len()))
.unwrap_or_else(|| panic!("enum is too big: bit-width overflowed"));
Self(
DynEnumTypeImpl {
variants,
@ -195,16 +192,16 @@ impl DynEnumType {
pub fn discriminant_bit_width(self) -> usize {
discriminant_bit_width_impl(self.variants().len())
}
pub fn is_passive(self) -> Result<bool, HitUndeducedType> {
Ok(true)
pub fn is_passive(self) -> bool {
true
}
pub fn is_storable(self) -> Result<bool, HitUndeducedType> {
pub fn is_storable(self) -> bool {
self.0.is_storable
}
pub fn is_castable_from_bits(self) -> Result<bool, HitUndeducedType> {
pub fn is_castable_from_bits(self) -> bool {
self.0.is_castable_from_bits
}
pub fn bit_width(self) -> Result<usize, HitUndeducedType> {
pub fn bit_width(self) -> usize {
self.0.bit_width
}
pub fn name_indexes(&self) -> &HashMap<Interned<str>, usize> {
@ -326,14 +323,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>,
>
CanonicalType = DynEnumType,
CanonicalValue = DynEnum,
MaskType = UIntType<1>,
MaskValue = UInt<1>,
MatchActiveScope = Scope,
MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>,
MatchVariantsIter = EnumMatchVariantsIter<Self>,
> + Connect<Self>
where
Self::Value: EnumValue + ToExpr<Type = Self>,
{
@ -349,7 +346,7 @@ where
&self,
variant_index: usize,
variant_value: Option<&VariantValue>,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
) -> Result<Interned<BitSlice>, ()> {
#[derive(Hash, Eq, PartialEq)]
struct VariantToBitsMemoize<E, V>(PhantomData<(E, V)>);
impl<E, V> Clone for VariantToBitsMemoize<E, V> {
@ -366,7 +363,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<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr>;
type Output = Result<Interned<BitSlice>, ()>;
fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> {
(&input.0, input.1, input.2.as_ref())
@ -389,22 +386,15 @@ where
fn inner(self, input: Self::InputRef<'_>) -> Self::Output {
let (ty, variant_index, variant_value) = input;
let ty = ty.canonical();
let bit_width = match ty.bit_width() {
Ok(v) => v,
Err(e) => return Ok(Err(e)),
};
let mut bits = BitVec::with_capacity(bit_width);
let mut bits = BitVec::with_capacity(ty.bit_width());
bits.extend_from_bitslice(
&variant_index.view_bits::<Lsb0>()[..ty.discriminant_bit_width()],
);
if let Some(variant_value) = variant_value {
match variant_value.to_expr().to_literal_bits()? {
Ok(variant_value) => bits.extend_from_bitslice(&variant_value),
Err(e) => return Ok(Err(e)),
}
bits.extend_from_bitslice(&variant_value.to_expr().to_literal_bits()?);
}
bits.resize(bit_width, false);
Ok(Ok(Intern::intern_owned(bits)))
bits.resize(ty.bit_width(), false);
Ok(Intern::intern_owned(bits))
}
}
VariantToBitsMemoize::<Self, VariantValue>(PhantomData).get((
@ -502,8 +492,6 @@ where
}
}
impl Connect<UndeducedType> for DynEnumType {}
impl Type for DynEnumType {
type CanonicalType = DynEnumType;
type Value = DynEnum;
@ -601,7 +589,7 @@ impl Value for DynEnum {
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
self.clone()
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
this.ty
.variant_to_bits(this.variant_index, this.variant_value.as_ref())
.unwrap()
@ -614,7 +602,7 @@ impl CanonicalValue for DynEnum {
fn value_enum_impl(this: &Self) -> ValueEnum {
ValueEnum::Enum(this.clone())
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
this.ty
.variant_to_bits(this.variant_index, this.variant_value.as_ref())
.unwrap()

View file

@ -17,7 +17,6 @@ use crate::{
DynCanonicalType, DynCanonicalValue, DynType, DynValue, DynValueTrait, Type, TypeWithDeref,
Value,
},
type_deduction::HitUndeducedType,
util::ConstBool,
valueless::Valueless,
wire::Wire,
@ -52,7 +51,8 @@ macro_rules! expr_enum {
$(Self::$Variant(v) => v.target(),)+
}
}
pub fn to_literal_bits(&self) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
#[allow(clippy::result_unit_err)]
pub fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
match self {
$(Self::$Variant(v) => v.to_literal_bits(),)+
}
@ -176,18 +176,6 @@ 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
@ -222,9 +210,8 @@ impl<T> Expr<T> {
{
Valueless { ty: self.ty() }
}
pub fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
#[allow(clippy::result_unit_err)]
pub fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.expr_enum().to_literal_bits()
}
#[track_caller]
@ -809,9 +796,8 @@ pub trait ExprTrait: ExprTraitBase {
fn valueless(&self) -> Valueless<Self::Type> {
Valueless { ty: self.ty() }
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr>;
#[allow(clippy::result_unit_err)]
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()>;
}
impl<T: ExprTrait> ExprTraitBase for T {}
@ -889,7 +875,7 @@ impl<T: Type> Literal<T> {
#[track_caller]
pub fn new_unchecked(value: T::CanonicalValue) -> Self {
assert!(
value.ty().is_passive().unwrap_or(true),
value.ty().is_passive(),
"can't have a literal with flipped fields"
);
Self { value }
@ -932,9 +918,7 @@ impl<T: Type> ExprTrait for Literal<T> {
None
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
Ok(self.value.to_bits())
}
}
@ -990,10 +974,8 @@ impl<T: Type> ExprTrait for ModuleIO<T> {
))
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
Err(NotALiteralExpr)
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
Err(())
}
}
@ -1026,10 +1008,8 @@ where
Some(Intern::intern_sized(self.canonical().into()))
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
Err(NotALiteralExpr)
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
Err(())
}
}
@ -1044,10 +1024,8 @@ impl<T: Type> ExprTrait for Wire<T> {
Some(Intern::intern_sized(self.to_dyn_canonical_wire().into()))
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
Err(NotALiteralExpr)
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
Err(())
}
}
@ -1062,10 +1040,8 @@ impl<T: Type> ExprTrait for Reg<T> {
Some(Intern::intern_sized(self.to_dyn_canonical_reg().into()))
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
Err(NotALiteralExpr)
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
Err(())
}
}
@ -1113,9 +1089,7 @@ where
fn target(&self) -> Option<Interned<Target>> {
Some(Intern::intern_sized(self.canonical().into()))
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
Err(NotALiteralExpr)
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
Err(())
}
}

View file

@ -6,12 +6,12 @@ use crate::{
clock::{Clock, ClockType, ToClock},
enum_::{DynEnumType, EnumType, EnumValue, VariantType},
expr::{
sealed, Expr, ExprEnum, ExprTrait, NotALiteralExpr, Target, TargetPathArrayElement,
TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, ToExpr,
sealed, Expr, ExprEnum, ExprTrait, Target, TargetPathArrayElement, TargetPathBundleField,
TargetPathDynArrayElement, TargetPathElement, ToExpr,
},
int::{
DynInt, DynIntType, DynSInt, DynSIntType, DynUInt, DynUIntType, Int, IntCmp, IntType,
IntTypeTrait, IntValue, StaticOrDynIntType, UInt, UIntType,
DynInt, DynIntType, DynSInt, DynSIntType, DynUInt, DynUIntType, StaticOrDynIntType, Int,
IntCmp, IntType, IntTypeTrait, IntValue, UInt, UIntType,
},
intern::{Intern, Interned},
reset::{
@ -19,9 +19,9 @@ use crate::{
ToReset, ToSyncReset,
},
ty::{
CanonicalType, CanonicalValue, DynCanonicalType, DynCanonicalValue, DynType, Type, Value,
CanonicalType, CanonicalValue, DynCanonicalType, DynCanonicalValue, DynType, DynValueTrait,
Type, Value,
},
type_deduction::HitUndeducedType,
util::{interned_bit, ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool},
valueless::{Valueless, ValuelessTr},
};
@ -33,43 +33,6 @@ 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,)*>
@ -93,9 +56,7 @@ macro_rules! fixed_ary_op {
$($expr_enum_body:tt)+
}
fn to_literal_bits(
&$to_literal_bits_self:ident,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&$to_literal_bits_self:ident) -> Result<Interned<BitSlice>, ()> {
$($to_literal_bits_body:tt)+
}
}
@ -212,9 +173,7 @@ 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<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&$to_literal_bits_self) -> Result<Interned<BitSlice>, ()> {
$($to_literal_bits_body)+
}
}
@ -248,8 +207,9 @@ macro_rules! unary_op {
Valueless::<$T>::from_canonical(arg.valueless()),
).ty,
#[cache]
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
unary_literal_bits(arg, |v| ops::$Op::$op($T::CanonicalValue::from_bit_slice(&v)).to_bits())
literal_bits: Result<Interned<BitSlice>, ()> = {
arg.to_literal_bits()
.map(|v| ops::$Op::$op($T::CanonicalValue::from_bit_slice(&v)).to_bits())
},
fn simulate(&self, sim_state: &mut SimState) -> _ {
@ -260,9 +220,7 @@ macro_rules! unary_op {
$($expr_enum_body)+
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -348,14 +306,18 @@ macro_rules! binary_op {
Valueless::<$RhsType>::from_canonical(rhs.valueless()),
).ty,
#[cache]
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()
})
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(())
},
fn simulate(&self, sim_state: &mut SimState) -> _ {
ops::$Op::$op(self.lhs.simulate(sim_state), self.rhs.simulate(sim_state))
@ -371,9 +333,7 @@ macro_rules! binary_op {
ConstBoolDispatch::True(v) => ExprEnum::$expr_enum_s(v.intern_sized()),
}
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -579,14 +539,18 @@ macro_rules! dyn_shift_op {
rhs.valueless(),
).ty,
#[cache]
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()
})
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(())
},
fn simulate(&self, sim_state: &mut SimState) -> _ {
ops::$Op::$op(self.lhs.simulate(sim_state), self.rhs.simulate(sim_state))
@ -601,9 +565,7 @@ macro_rules! dyn_shift_op {
ConstBoolDispatch::True(v) => ExprEnum::$expr_enum_s(v.intern_sized()),
}
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -684,14 +646,15 @@ 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<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
unary_literal_bits(lhs, |lhs| {
ops::$Op::$op(
LhsType::CanonicalValue::from_bit_slice(&lhs),
rhs,
)
.to_bits()
})
literal_bits: Result<Interned<BitSlice>, ()> = {
lhs.to_literal_bits()
.map(|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)
@ -706,9 +669,7 @@ macro_rules! fixed_shift_op {
ConstBoolDispatch::True(v) => ExprEnum::$expr_enum_s(v.intern_sized()),
}
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -778,14 +739,18 @@ macro_rules! cmp_op {
#[type]
ty: Output = StaticOrDynIntType::new(),
#[cache]
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()),
)
})
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(())
},
fn simulate(&self, sim_state: &mut SimState) -> _ {
self.lhs.simulate(sim_state).$fn(self.rhs.simulate(sim_state)).into_canonical()
@ -803,9 +768,7 @@ macro_rules! cmp_op {
}
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -893,8 +856,8 @@ fixed_ary_op! {
#[type(ty)]
pub ty: ToType = ty,
#[cache]
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
unary_literal_bits(value, |literal_bits| {
literal_bits: Result<Interned<BitSlice>, ()> = {
value.to_literal_bits().map(|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);
@ -938,9 +901,7 @@ fixed_ary_op! {
}
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -995,8 +956,8 @@ fixed_ary_op! {
#[type]
ty: DynUIntType = base.valueless().slice(range.clone()).ty,
#[cache]
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
unary_literal_bits(base, |base| {
literal_bits: Result<Interned<BitSlice>, ()> = {
base.to_literal_bits().map(|base| {
base[range.clone()].intern()
})
},
@ -1015,9 +976,7 @@ fixed_ary_op! {
}
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -1151,8 +1110,8 @@ macro_rules! reduce_bit_op {
#[type]
ty: Output = StaticOrDynIntType::new(),
#[cache]
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
unary_literal_bits(arg, |$bits| interned_bit($literal_bits_bool))
literal_bits: Result<Interned<BitSlice>, ()> = {
arg.to_literal_bits().map(|$bits| interned_bit($literal_bits_bool))
},
fn simulate(&self, sim_state: &mut SimState) -> _ {
todo!()
@ -1162,9 +1121,7 @@ macro_rules! reduce_bit_op {
ExprEnum::$name($name::new_unchecked(self.arg).intern_sized())
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -1223,9 +1180,9 @@ fixed_ary_op! {
Field::from_canonical_type(field_ty.expect("field type doesn't match type generic"))
},
#[cache]
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())
literal_bits: Result<Interned<BitSlice>, ()> = {
base.to_literal_bits().map(|base| {
base[base_ty.field_offsets()[index]..][..field.ty.bit_width()].intern()
})
},
#[target]
@ -1242,9 +1199,7 @@ fixed_ary_op! {
ExprEnum::FieldAccess(FieldAccess::new_unchecked(self.base, self.name).intern_sized())
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -1284,9 +1239,9 @@ fixed_ary_op! {
base_ty.variants()[variant_index].ty.unwrap_or_else(|| ().canonical_dyn()),
),
#[cache]
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())
literal_bits: Result<Interned<BitSlice>, ()> = {
base.to_literal_bits().map(|base| {
base[base_ty.discriminant_bit_width()..][..ty.bit_width()].intern()
})
},
fn simulate(&self, sim_state: &mut SimState) -> _ {
@ -1300,9 +1255,7 @@ fixed_ary_op! {
).intern_sized())
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -1339,7 +1292,7 @@ fixed_ary_op! {
pub struct CastToBits<> where () {
value: Expr<DynCanonicalValue>,
#[type]
ty: DynUIntType = DynUIntType::new(value.ty().bit_width().unwrap_or_else(|e| panic!("can't convert undeduced type to bits: {e}"))),
ty: DynUIntType = DynUIntType::new(value.ty().bit_width()),
fn simulate(&self, sim_state: &mut SimState) -> _ {
todo!()
}
@ -1348,9 +1301,7 @@ fixed_ary_op! {
ExprEnum::CastToBits(self.intern())
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.value.to_literal_bits()
}
}
@ -1376,10 +1327,8 @@ fixed_ary_op! {
value: Expr<DynUInt>,
#[type(ty)]
ty: T = {
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");
}
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");
ty
},
fn simulate(&self, sim_state: &mut SimState) -> _ {
@ -1392,9 +1341,7 @@ fixed_ary_op! {
)
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.value.to_literal_bits()
}
}
@ -1445,9 +1392,7 @@ macro_rules! cast_bit_to_typed_bit {
ExprEnum::$Op($Op::new_unchecked(self.value).intern_sized())
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.value.to_literal_bits()
}
}
@ -1607,18 +1552,17 @@ fixed_ary_op! {
ty
},
#[cache]
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = (|| {
let mut bits = ty.bit_width().map(BitVec::with_capacity);
literal_bits: Result<Interned<BitSlice>, ()> = {
let mut bits = Some(BitVec::with_capacity(ty.bit_width()));
for element in elements {
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),
}
let Ok(element_bits) = element.to_literal_bits() else {
bits = None;
break;
};
bits.as_mut().unwrap().extend_from_bitslice(&element_bits);
}
Ok(bits.map(Intern::intern_owned))
})(),
bits.map(Intern::intern_owned).ok_or(())
},
fn simulate(&self, sim_state: &mut SimState) -> _ {
todo!()
}
@ -1627,9 +1571,7 @@ fixed_ary_op! {
ExprEnum::ArrayLiteral(self.canonical().intern_sized())
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -1661,13 +1603,13 @@ fixed_ary_op! {
base_ty.element().clone()
},
#[cache]
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = {
literal_bits: Result<Interned<BitSlice>, ()> = {
let base_ty = base.ty();
try_unary_literal_bits(base, |base| {
let element_bit_width = base_ty.element().bit_width()?;
let element_bit_width = base_ty.element().bit_width();
base.to_literal_bits().map(|base| {
let start = index * element_bit_width;
let end = start + element_bit_width;
Ok(base[start..end].intern())
base[start..end].intern()
})
},
#[target]
@ -1684,9 +1626,7 @@ fixed_ary_op! {
ExprEnum::ArrayIndex(ArrayIndex::new_unchecked(self.base, self.index).intern_sized())
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -1715,32 +1655,18 @@ fixed_ary_op! {
base_ty.element().clone()
},
#[cache]
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = (|| {
literal_bits: Result<Interned<BitSlice>, ()> = {
let base_ty = base.ty();
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)
})(),
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(())
},
#[target]
target: Option<Interned<Target>> = base.target().map(|base| {
Intern::intern_sized(base.join(
@ -1757,9 +1683,7 @@ fixed_ary_op! {
)
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -1804,7 +1728,7 @@ impl<
fn expr_index(this: Expr<Self>, index: Expr<IntValue<Idx>>) -> Expr<Self::OutputValue> {
let index: Expr<DynUInt> = index.canonical();
if let Ok(Ok(index)) = index.to_literal_bits() {
if let Ok(index) = index.to_literal_bits() {
let index = DynUInt::from_bit_slice(&index)
.uint_value()
.try_into()
@ -1834,7 +1758,7 @@ fixed_ary_op! {
#[type(ty)]
ty: BundleTy = {
assert!(
ty.is_passive().unwrap_or(true),
ty.is_passive(),
concat!(
"bundle literal must be a passive type (no ",
"#[flip] fields and all fields must be passive types)",
@ -1851,18 +1775,17 @@ fixed_ary_op! {
ty
},
#[cache]
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> = (|| {
let mut bits = ty.bit_width().map(BitVec::with_capacity);
literal_bits: Result<Interned<BitSlice>, ()> = {
let mut bits = Some(BitVec::new());
for field in fields {
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),
}
let Ok(v) = field.to_literal_bits() else {
bits = None;
break;
};
bits.as_mut().unwrap().extend_from_bitslice(&v);
}
Ok(bits.map(Intern::intern_owned))
})(),
bits.map(Intern::intern_owned).ok_or(())
},
fn simulate(&self, sim_state: &mut SimState) -> _ {
todo!()
}
@ -1871,9 +1794,7 @@ fixed_ary_op! {
ExprEnum::BundleLiteral(self.canonical().intern_sized())
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}
@ -1910,7 +1831,7 @@ fixed_ary_op! {
ty
},
#[cache]
literal_bits: Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> =
literal_bits: Result<Interned<BitSlice>, ()> =
ty.variant_to_bits(variant_index, variant_value.as_ref()),
fn simulate(&self, sim_state: &mut SimState) -> _ {
todo!()
@ -1920,9 +1841,7 @@ fixed_ary_op! {
ExprEnum::EnumLiteral(self.canonical().intern_sized())
}
fn to_literal_bits(
&self,
) -> Result<Result<Interned<BitSlice>, HitUndeducedType>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, ()> {
self.literal_bits
}
}

View file

@ -27,7 +27,6 @@ use crate::{
DynCanonicalType, DynCanonicalValue, DynCanonicalValueTrait, DynType, DynValue, Type,
TypeEnum, Value, ValueEnum,
},
type_deduction::HitUndeducedType,
util::{
const_str_array_is_strictly_ascending, BitSliceWriteWithBase, DebugAsRawString,
GenericConstBool,
@ -441,7 +440,6 @@ impl TypeState {
TypeEnum::AsyncReset(AsyncResetType {}) => "AsyncReset".into(),
TypeEnum::SyncReset(SyncResetType {}) => "UInt<1>".into(),
TypeEnum::Reset(ResetType {}) => "Reset".into(),
TypeEnum::Deduce(_) => handle_undeduced_type(HitUndeducedType),
}
}
}
@ -470,25 +468,6 @@ 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,
@ -1033,12 +1012,10 @@ impl<'a> Exporter<'a> {
name,
flipped: _,
ty: field_ty,
}| {
FieldType {
name,
flipped: false,
ty: DynUIntType::new(field_ty.bit_width().unwrap_undeduced()).canonical_dyn(),
}
}| FieldType {
name,
flipped: false,
ty: DynUIntType::new(field_ty.bit_width()).canonical_dyn(),
},
)));
let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty);
@ -1070,7 +1047,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().unwrap_undeduced()
ty.bit_width()
));
let cat_expr = cat_expr.expect("bundle already checked to have fields");
definitions.add_definition_line(format_args!("{extra_indent}connect {retval}, {cat_expr}"));
@ -1089,7 +1066,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().unwrap_undeduced()
ty.bit_width()
));
definitions.add_definition_line(format_args!("{extra_indent}match {value_str}:"));
let _match_arms_indent = extra_indent.push();
@ -1113,7 +1090,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().unwrap_undeduced(),
ty.bit_width(),
));
} else {
definitions.add_definition_line(format_args!(
@ -1123,7 +1100,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().unwrap_undeduced(),
ty.bit_width(),
));
}
}
@ -1147,7 +1124,7 @@ impl<'a> Exporter<'a> {
extra_indent,
);
}
let element_width = ty.element().bit_width().unwrap_undeduced();
let element_width = ty.element().bit_width();
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}>[{}]",
@ -1173,7 +1150,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().unwrap_undeduced()
ty.bit_width()
));
let cat_expr = cat_expr.expect("array already checked to have elements");
definitions.add_definition_line(format_args!("{extra_indent}connect {retval}, {cat_expr}"));
@ -1201,7 +1178,6 @@ 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(
@ -1223,12 +1199,10 @@ impl<'a> Exporter<'a> {
name,
flipped: _,
ty: field_ty,
}| {
FieldType {
name,
flipped: false,
ty: DynUIntType::new(field_ty.bit_width().unwrap_undeduced()).canonical_dyn(),
}
}| FieldType {
name,
flipped: false,
ty: DynUIntType::new(field_ty.bit_width()).canonical_dyn(),
},
)));
let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty);
@ -1244,9 +1218,7 @@ 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().unwrap_undeduced().checked_sub(1usize)
{
if let Some(field_bit_width_minus_one) = field.ty.bit_width().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
@ -1300,7 +1272,7 @@ impl<'a> Exporter<'a> {
return retval.to_string();
}
let discriminant_bit_width = ty.discriminant_bit_width();
let body_bit_width = ty.bit_width().unwrap_undeduced() - discriminant_bit_width;
let body_bit_width = ty.bit_width() - 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!(
@ -1356,7 +1328,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().unwrap_undeduced();
let element_bit_width = ty.element().bit_width();
if ty.is_empty() || element_bit_width == 0 {
definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}"));
return retval.to_string();
@ -1410,7 +1382,6 @@ 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>>>(
@ -1702,13 +1673,13 @@ impl<'a> Exporter<'a> {
) -> Result<(), WrappedError> {
assert_eq!(
initial_value.len(),
array_type.bit_width().unwrap_undeduced(),
array_type.bit_width(),
"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().unwrap_undeduced();
let element_bit_width = array_type.element().bit_width();
let mut contents = String::new();
let hex_or_binary = if element_bit_width % 4 == 0 {
HexOrBinary::Hex
@ -2420,7 +2391,7 @@ fn export_impl(
file_backend: &mut dyn WrappedFileBackendTrait,
top_module: Interned<Module<DynBundle>>,
) -> Result<(), WrappedError> {
let top_module = simplify_memories(top_module).unwrap_undeduced();
let top_module = simplify_memories(top_module);
let indent_depth = Cell::new(0);
let mut global_ns = Namespace::default();
let circuit_name = global_ns.get(top_module.name_id());

View file

@ -8,7 +8,6 @@ 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,
};
@ -340,7 +339,22 @@ impl<
// correct since slice_and_shift ensures we're not trying to slice out of range
IntValue::with_type(ty, &self.uint_value >> shift)
}
pub fn to_bits(&self) -> Interned<BitSlice> {
}
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> {
#[derive(Hash, Eq, PartialEq)]
struct ToBitsMemoize<T>(PhantomData<T>);
impl<T> Clone for ToBitsMemoize<T> {
@ -373,25 +387,7 @@ impl<
Intern::intern_owned(bits)
}
}
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))
ToBitsMemoize::<Self>(PhantomData).get(this)
}
}
@ -1115,8 +1111,6 @@ 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>>;
@ -1182,7 +1176,7 @@ impl<Signed: GenericConstBool> CanonicalValue for IntValue<DynIntType<Signed>> {
ValueEnum::UInt(this.clone().as_same_width_uint())
}
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
<Self as Value>::to_bits_impl(this)
}
}
@ -1209,9 +1203,7 @@ 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)
}
@ -1241,11 +1233,6 @@ 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>>;

View file

@ -40,7 +40,6 @@ 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;

View file

@ -13,7 +13,6 @@ use crate::{
module::ScopedNameId,
source_location::SourceLocation,
ty::{AsMask, DynCanonicalType, DynCanonicalValue, DynType, Type, Value},
type_deduction::HitUndeducedType,
util::DebugAsDisplay,
};
use bitvec::slice::BitSlice;
@ -493,7 +492,7 @@ impl<T: PortType> MemPort<T> {
mem_element_type: Interned<dyn DynCanonicalType>,
) -> Self {
assert!(
mem_element_type.is_storable().unwrap_or(true),
mem_element_type.is_storable(),
"memory element type must be a storable type"
);
Self {
@ -627,7 +626,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().unwrap_or(true),
expected_mem_element_type.is_storable(),
"memory element type must be a storable type"
);
for (index, port) in ports.iter().enumerate() {
@ -847,21 +846,19 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
initial_value: Interned<BitSlice>,
) -> Interned<BitSlice> {
if let Some(depth) = depth {
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",
);
}
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",
);
}
assert!(
initial_value
.len()
.checked_rem(mem_element_type.bit_width().unwrap_or(1))
.checked_rem(mem_element_type.bit_width())
.unwrap_or(initial_value.len())
== 0,
"Mem's initializer bit length must be a multiple of the element type's bit width",
@ -890,17 +887,8 @@ 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!(
Ok(retval.len()),
retval.len(),
initial_value_ty.bit_width(),
"initial value produced wrong literal bits length"
);
@ -914,7 +902,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().unwrap_or(true),
canonical_mem_element_type.is_storable(),
"memory element type must be a storable type"
);
let target = Rc::new(RefCell::new(MemBuilderTarget {
@ -1073,10 +1061,9 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
target.depth,
initial_value,
));
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);
}
let 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 {

View file

@ -20,7 +20,6 @@ use crate::{
CanonicalType, Connect, DynCanonicalType, DynCanonicalValue, DynType, StaticValue, Type,
TypeEnum, Value,
},
type_deduction::HitUndeducedType,
util::ConstBool,
wire::Wire,
};
@ -1415,42 +1414,42 @@ impl TargetState {
}
}
}
fn new(target: Interned<Target>, declared_in_block: usize) -> Result<Self, HitUndeducedType> {
Ok(Self {
fn new(target: Interned<Target>, declared_in_block: usize) -> Self {
Self {
target,
inner: match target.canonical_ty().type_enum() {
TypeEnum::BundleType(ty) => TargetStateInner::Decomposed {
subtargets: ty
.fields()
.iter()
.map(|&field| -> Result<_, HitUndeducedType> {
.map(|&field| {
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::<Result<_, _>>()?,
.collect(),
},
TypeEnum::ArrayType(ty) => TargetStateInner::Decomposed {
subtargets: (0..ty.len())
.map(|index| -> Result<_, HitUndeducedType> {
.map(|index| {
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::<Result<_, _>>()?,
.collect(),
},
TypeEnum::EnumType(_)
| TypeEnum::UInt(_)
@ -1462,9 +1461,8 @@ impl TargetState {
declared_in_block,
written_in_blocks: RefCell::default(),
},
TypeEnum::Deduce(_) => return Err(HitUndeducedType),
},
})
}
}
}
@ -1526,11 +1524,7 @@ 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,
) -> Result<(), HitUndeducedType> {
fn insert_new_base(&mut self, target_base: Interned<TargetBase>, declared_in_block: usize) {
match self.target_states.entry(target_base) {
Entry::Occupied(_) => panic!(
"at {}: duplicate declaration: {target_base}",
@ -1540,10 +1534,9 @@ impl AssertValidityState {
entry.insert(TargetState::new(
Target::intern_sized(target_base.into()),
declared_in_block,
)?);
));
}
}
Ok(())
}
fn set_connect_target_written(
target_state: &TargetState,
@ -1632,30 +1625,29 @@ 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) -> Result<(), HitUndeducedType> {
fn assert_subtree_validity(&mut self, block: usize) {
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 {
@ -1670,7 +1662,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(
@ -1679,23 +1671,22 @@ 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) {
@ -1707,11 +1698,10 @@ impl AssertValidityState {
ModuleBody::Normal(NormalModuleBody { body }) => {
let body = self.make_block_index(body);
assert_eq!(body, 0);
if let Ok(()) = self.assert_subtree_validity(body) {
for (base, state) in &self.target_states {
if base.must_connect_to() {
state.assert_written();
}
self.assert_subtree_validity(body);
for (base, state) in &self.target_states {
if base.must_connect_to() {
state.assert_written();
}
}
}
@ -2377,7 +2367,7 @@ where
match rhs.flow() {
Flow::Source | Flow::Duplex => {}
Flow::Sink => assert!(
rhs.ty().is_passive().unwrap_or(true),
rhs.ty().is_passive(),
"can't connect from sink with non-passive type"
),
}

View file

@ -14,7 +14,6 @@ use crate::{
},
source_location::SourceLocation,
ty::{DynCanonicalType, DynCanonicalValue, Type, TypeEnum, Value, ValueEnum},
type_deduction::HitUndeducedType,
wire::Wire,
};
use core::fmt;
@ -23,7 +22,6 @@ use hashbrown::HashMap;
#[derive(Debug)]
pub enum SimplifyEnumsError {
EnumIsNotCastableFromBits { enum_type: DynEnumType },
HitUndeducedType(HitUndeducedType),
}
impl fmt::Display for SimplifyEnumsError {
@ -33,19 +31,12 @@ 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,
@ -78,7 +69,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
@ -95,7 +86,7 @@ impl State {
},
))),
body: DynUIntType::new(
enum_type.bit_width()? - enum_type.discriminant_bit_width(),
enum_type.bit_width() - enum_type.discriminant_bit_width(),
),
})
}
@ -104,12 +95,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());
@ -117,14 +108,11 @@ impl State {
}
}
fn value_to_uint<T: Value>(
value: Option<&T>,
target_ty: DynUIntType,
) -> Result<DynUInt, HitUndeducedType> {
fn value_to_uint<T: Value>(value: Option<&T>, target_ty: DynUIntType) -> DynUInt {
let Some(value) = value else {
return Ok(DynUInt::with_type(target_ty, 0u8));
return DynUInt::with_type(target_ty, 0u8);
};
Ok(DynUInt::from_bit_slice(&value.to_bits()?))
DynUInt::from_bit_slice(&value.to_bits())
}
fn connect_port(
@ -132,7 +120,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(
@ -143,25 +131,24 @@ fn connect_port(
})
.into(),
);
return Ok(());
return;
}
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(_)) => {
@ -173,14 +160,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(_), _)
@ -197,7 +184,6 @@ fn connect_port(
rhs.canonical_type().type_enum(),
),
}
Ok(())
}
impl Folder for State {
@ -254,7 +240,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,
)
@ -282,7 +268,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(),
@ -298,7 +284,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()
@ -442,7 +428,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());
}
@ -576,7 +562,6 @@ impl Folder for State {
| TypeEnum::AsyncReset(_)
| TypeEnum::SyncReset(_)
| TypeEnum::Reset(_) => type_enum.default_fold(self),
TypeEnum::Deduce(_) => Err(HitUndeducedType.into()),
}
}
@ -590,7 +575,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(),
),
@ -600,12 +585,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),
})

View file

@ -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) -> Result<Self, HitUndeducedType> {
Ok(match element_type {
fn new(element_type: TypeEnum) -> Self {
match element_type {
TypeEnum::BundleType(bundle_ty) => MemSplit::Bundle {
fields: bundle_ty
.fields()
.into_iter()
.map(|field| Ok(Self::new(field.ty.type_enum())?.mark_changed_element_type()))
.collect::<Result<_, _>>()?,
.map(|field| Self::new(field.ty.type_enum()).mark_changed_element_type())
.collect(),
},
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,15 +157,14 @@ 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),
})
}
}
}
@ -272,7 +271,7 @@ struct SplitMemState<'a, 'b> {
}
impl SplitMemState<'_, '_> {
fn split_mem(self) -> Result<(), HitUndeducedType> {
fn split_mem(self) {
let outer_mem_name_path_len = self.mem_name_path.len();
match self.split {
MemSplit::Bundle { fields } => {
@ -288,7 +287,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| {
@ -306,7 +305,7 @@ impl SplitMemState<'_, '_> {
split_state_stack: self.split_state_stack,
mem_state: self.mem_state,
}
.split_mem()?;
.split_mem();
self.split_state_stack.pop();
}
}
@ -322,7 +321,7 @@ impl SplitMemState<'_, '_> {
*single_type,
self.mem_name_path,
self.split_state_stack.top(),
)?;
);
for (port, wire) in new_mem
.ports()
.into_iter()
@ -357,7 +356,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();
@ -380,12 +379,11 @@ impl SplitMemState<'_, '_> {
split_state_stack: self.split_state_stack,
mem_state: self.mem_state,
}
.split_mem()?;
.split_mem();
self.split_state_stack.pop();
}
}
}
Ok(())
}
}
@ -467,7 +465,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>,
@ -601,11 +599,9 @@ 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,
@ -615,7 +611,7 @@ impl ModuleState {
single_type: SingleType,
mem_name_path: &str,
split_state: &SplitState<'_>,
) -> Result<Mem<[DynCanonicalValue]>, HitUndeducedType> {
) -> Mem<[DynCanonicalValue]> {
let mem_name = self.name_id_gen.gen(Intern::intern_owned(format!(
"{}{mem_name_path}",
input_mem.scoped_name().1 .0
@ -629,9 +625,8 @@ 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_bit_width);
let mut bits = BitVec::with_capacity(output_array_type.bit_width());
for element in initial_value.iter() {
bits.extend_from_bitslice(element);
}
@ -701,18 +696,18 @@ impl ModuleState {
port_rdata,
port_wdata,
port_wmask,
)?;
);
}
Ok(output_mem)
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,
@ -810,12 +805,11 @@ impl ModuleState {
),
mem_state: &mem_state,
}
.split_mem()?;
.split_mem();
mem_state
}
};
self.memories.insert(input_mem.scoped_name(), mem_state);
Ok(())
}
}
@ -864,7 +858,7 @@ impl DerefMut for PushedState<'_> {
}
impl Folder for State {
type Error = HitUndeducedType;
type Error = Infallible;
fn fold_module<T: BundleValue>(&mut self, v: Module<T>) -> Result<Module<T>, Self::Error>
where
@ -908,11 +902,13 @@ 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)?;
}
for stmt in input_stmts {
output_stmts.push(stmt.fold(self)?);
module_state.process_mem(input_mem, &mut output_mems, &mut output_stmts);
}
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),
@ -937,8 +933,8 @@ impl Folder for State {
}
}
pub fn simplify_memories(
module: Interned<Module<DynBundle>>,
) -> Result<Interned<Module<DynBundle>>, HitUndeducedType> {
module.fold(&mut State::default())
pub fn simplify_memories(module: Interned<Module<DynBundle>>) -> Interned<Module<DynBundle>> {
module
.fold(&mut State::default())
.unwrap_or_else(|v| match v {})
}

View file

@ -12,8 +12,8 @@ use crate::{
TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, ToExpr,
},
int::{
DynInt, DynIntType, DynSInt, DynSIntType, DynUInt, DynUIntType, IntType, IntTypeTrait,
StaticOrDynIntType,
DynInt, DynIntType, DynSInt, DynSIntType, DynUInt, DynUIntType, StaticOrDynIntType, IntType,
IntTypeTrait,
},
intern::{Intern, Interned},
memory::{Mem, MemPort, PortKind, PortName, PortType, ReadUnderWrite},
@ -27,7 +27,6 @@ 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,
};

View file

@ -106,10 +106,7 @@ impl<T: Type> Reg<T> {
clock_domain: Expr<ClockDomain>,
init: Option<Expr<T::Value>>,
) -> Self {
assert!(
ty.is_storable().unwrap_or(true),
"register type must be a storable type"
);
assert!(ty.is_storable(), "register type must be a storable type");
if let Some(init) = init {
assert_eq!(ty, init.ty(), "register's type must match init type");
}

View file

@ -9,7 +9,6 @@ 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;
@ -25,8 +24,6 @@ impl AsyncResetType {
}
}
impl Connect<UndeducedType> for AsyncResetType {}
impl Type for AsyncResetType {
type Value = AsyncReset;
type CanonicalType = AsyncResetType;
@ -94,8 +91,8 @@ impl Value for AsyncReset {
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
*self
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
Ok(interned_bit(this.0))
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
interned_bit(this.0)
}
}
@ -103,8 +100,8 @@ impl CanonicalValue for AsyncReset {
fn value_enum_impl(this: &Self) -> ValueEnum {
ValueEnum::AsyncReset(*this)
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
Ok(interned_bit(this.0))
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
interned_bit(this.0)
}
}
@ -117,8 +114,6 @@ impl SyncResetType {
}
}
impl Connect<UndeducedType> for SyncResetType {}
impl Type for SyncResetType {
type CanonicalType = SyncResetType;
type Value = SyncReset;
@ -186,8 +181,8 @@ impl Value for SyncReset {
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
*self
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
Ok(interned_bit(this.0))
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
interned_bit(this.0)
}
}
@ -195,8 +190,8 @@ impl CanonicalValue for SyncReset {
fn value_enum_impl(this: &Self) -> ValueEnum {
ValueEnum::SyncReset(*this)
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
Ok(interned_bit(this.0))
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
interned_bit(this.0)
}
}
@ -209,8 +204,6 @@ impl ResetType {
}
}
impl Connect<UndeducedType> for ResetType {}
impl Type for ResetType {
type Value = Reset;
type CanonicalType = ResetType;
@ -278,7 +271,7 @@ impl Value for Reset {
fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
*self
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
match *this {}
}
}
@ -287,7 +280,7 @@ impl CanonicalValue for Reset {
fn value_enum_impl(this: &Self) -> ValueEnum {
ValueEnum::Reset(*this)
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
match *this {}
}
}

View file

@ -14,7 +14,6 @@ use crate::{
},
reset::{AsyncReset, AsyncResetType, Reset, ResetType, SyncReset, SyncResetType},
source_location::SourceLocation,
type_deduction::{Deduce, HitUndeducedType, UndeducedType},
util::{iter_eq_by, GenericConstBool},
valueless::Valueless,
};
@ -47,7 +46,6 @@ pub enum TypeEnum {
AsyncReset(AsyncResetType),
SyncReset(SyncResetType),
Reset(ResetType),
Deduce(UndeducedType),
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
@ -62,7 +60,6 @@ pub enum CanonicalTypeKind {
SyncReset,
Reset,
DynCanonicalType,
Deduce,
}
impl CanonicalTypeKind {
@ -78,7 +75,6 @@ impl CanonicalTypeKind {
CanonicalTypeKind::SyncReset => "Expr<SyncReset>",
CanonicalTypeKind::Reset => "Expr<Reset>",
CanonicalTypeKind::DynCanonicalType => "Expr<DynCanonicalValue>",
CanonicalTypeKind::Deduce => "Expr<Deduce>",
}
}
}
@ -97,61 +93,57 @@ pub enum ValueEnum {
}
impl TypeEnum {
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()?,
pub fn is_passive(self) -> bool {
match self {
TypeEnum::BundleType(ty) => DynBundleType::is_passive(ty),
TypeEnum::EnumType(ty) => DynEnumType::is_passive(ty),
TypeEnum::ArrayType(ty) => ty.element().is_passive(),
TypeEnum::UInt(_) => true,
TypeEnum::SInt(_) => true,
TypeEnum::Clock(_) => true,
TypeEnum::AsyncReset(_) => true,
TypeEnum::SyncReset(_) => true,
TypeEnum::Reset(_) => true,
TypeEnum::Deduce(_) => return Err(HitUndeducedType),
})
}
}
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()?,
pub fn is_storable(self) -> bool {
match self {
TypeEnum::BundleType(ty) => DynBundleType::is_storable(ty),
TypeEnum::EnumType(ty) => DynEnumType::is_storable(ty),
TypeEnum::ArrayType(ty) => ty.element().is_storable(),
TypeEnum::UInt(_) => true,
TypeEnum::SInt(_) => true,
TypeEnum::Clock(_) => false,
TypeEnum::AsyncReset(_) => false,
TypeEnum::SyncReset(_) => false,
TypeEnum::Reset(_) => false,
TypeEnum::Deduce(_) => return Err(HitUndeducedType),
})
}
}
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()?,
pub fn is_castable_from_bits(self) -> bool {
match self {
TypeEnum::BundleType(ty) => DynBundleType::is_castable_from_bits(ty),
TypeEnum::EnumType(ty) => DynEnumType::is_castable_from_bits(ty),
TypeEnum::ArrayType(ty) => ty.element().is_castable_from_bits(),
TypeEnum::UInt(_) => true,
TypeEnum::SInt(_) => true,
TypeEnum::Clock(_) => true,
TypeEnum::AsyncReset(_) => true,
TypeEnum::SyncReset(_) => true,
TypeEnum::Reset(_) => false, // Reset is not castable from bits because we don't know if it's async or sync
TypeEnum::Deduce(_) => return Err(HitUndeducedType),
})
}
}
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)?,
pub fn bit_width(self) -> usize {
match self {
TypeEnum::BundleType(ty) => DynBundleType::bit_width(ty),
TypeEnum::EnumType(ty) => DynEnumType::bit_width(ty),
TypeEnum::ArrayType(ty) => ArrayType::bit_width(&ty),
TypeEnum::UInt(ty) => ty.width,
TypeEnum::SInt(ty) => ty.width,
TypeEnum::Clock(ClockType)
| TypeEnum::AsyncReset(AsyncResetType)
| TypeEnum::SyncReset(SyncResetType)
| TypeEnum::Reset(ResetType) => 1,
TypeEnum::Deduce(_) => return Err(HitUndeducedType),
})
}
}
pub fn bundle_type(self) -> Option<DynBundleType> {
if let TypeEnum::BundleType(retval) = self {
@ -216,13 +208,6 @@ 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(),
@ -234,7 +219,6 @@ 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> {
@ -248,7 +232,6 @@ 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(),
}
}
}
@ -259,10 +242,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) -> 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 is_passive(&self) -> bool;
fn is_storable(&self) -> bool;
fn is_castable_from_bits(&self) -> bool;
fn bit_width(&self) -> usize;
fn as_dyn_type(&self) -> &dyn DynType;
fn as_dyn_canonical_type(&self) -> Option<&dyn DynCanonicalType>;
#[deprecated = "use <dyn DynType>::downcast or <dyn DynCanonicalType>::downcast instead, they properly handle Interned<dyn DynType> and Interned<dyn DynCanonicalType>"]
@ -311,19 +294,19 @@ impl<T: Type> DynType for T {
self.type_enum()
}
fn is_passive(&self) -> Result<bool, HitUndeducedType> {
fn is_passive(&self) -> bool {
self.type_enum().is_passive()
}
fn is_storable(&self) -> Result<bool, HitUndeducedType> {
fn is_storable(&self) -> bool {
self.type_enum().is_storable()
}
fn is_castable_from_bits(&self) -> Result<bool, HitUndeducedType> {
fn is_castable_from_bits(&self) -> bool {
self.type_enum().is_castable_from_bits()
}
fn bit_width(&self) -> Result<usize, HitUndeducedType> {
fn bit_width(&self) -> usize {
self.type_enum().bit_width()
}
@ -476,9 +459,7 @@ impl<T: 'static + Send + Sync> MatchVariantAndInactiveScope for MatchVariantWith
}
}
pub trait Type:
DynType + Clone + Hash + Eq + Intern + Connect<Self> + Connect<UndeducedType>
{
pub trait Type: DynType + Clone + Hash + Eq + Intern + Connect<Self> {
type CanonicalType: CanonicalType<
CanonicalType = Self::CanonicalType,
CanonicalValue = Self::CanonicalValue,
@ -581,9 +562,8 @@ pub trait CanonicalType:
fn can_connect(&self, other: &Self) -> bool {
macro_rules! unwrap_other {
($var:ident = $fn:ident()) => {
let other_ty = other.type_enum();
let Some($var) = other_ty.$fn() else {
return other_ty.undeduced().is_some();
let Some($var) = other.type_enum().$fn() else {
return false;
};
};
}
@ -639,7 +619,6 @@ pub trait CanonicalType:
unwrap_other!(other = reset());
this == other
}
TypeEnum::Deduce(_) => true,
}
}
}
@ -662,7 +641,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) -> Result<Interned<BitSlice>, HitUndeducedType>;
fn to_bits(&self) -> Interned<BitSlice>;
}
macro_rules! dyn_value {
@ -728,7 +707,7 @@ impl Value for DynValue {
self.0.to_canonical_dyn()
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
this.0.to_bits()
}
}
@ -764,7 +743,7 @@ impl Value for DynCanonicalValue {
self.0.to_canonical_dyn()
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
<Self as CanonicalValue>::to_bits_impl(this)
}
}
@ -780,7 +759,7 @@ impl CanonicalValue for DynCanonicalValue {
this.0.value_enum()
}
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
this.0.to_bits()
}
}
@ -828,7 +807,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) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
<<Self::Type as Type>::CanonicalValue as CanonicalValue>::to_bits_impl(&this.to_canonical())
}
}
@ -865,7 +844,7 @@ where
)
}
fn value_enum_impl(this: &Self) -> ValueEnum;
fn to_bits_impl(this: &Self) -> Result<Interned<BitSlice>, HitUndeducedType>;
fn to_bits_impl(this: &Self) -> Interned<BitSlice>;
}
impl<T: Value> DynValueTrait for T
@ -905,13 +884,11 @@ where
self
}
fn to_bits(&self) -> Result<Interned<BitSlice>, HitUndeducedType> {
fn to_bits(&self) -> Interned<BitSlice> {
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;
@ -1000,8 +977,6 @@ 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> {
@ -1039,7 +1014,3 @@ 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 {}

View file

@ -1,136 +0,0 @@
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 {}
}
}

View file

@ -57,8 +57,7 @@
"Clock": "Visible",
"AsyncReset": "Visible",
"SyncReset": "Visible",
"Reset": "Visible",
"Deduce": "Visible"
"Reset": "Visible"
}
},
"DynBundleType": {
@ -121,11 +120,6 @@
"$kind": "Struct"
}
},
"UndeducedType": {
"data": {
"$kind": "Opaque"
}
},
"AsyncResetType": {
"data": {
"$kind": "Struct"