forked from libre-chip/fayalite
		
	
		
			
				
	
	
		
			796 lines
		
	
	
	
		
			25 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			796 lines
		
	
	
	
		
			25 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
						|
// See Notices.txt for copyright information
 | 
						|
use crate::{
 | 
						|
    expr::{ops::BundleLiteral, Expr, ToExpr},
 | 
						|
    intern::{
 | 
						|
        Intern, Interned, InternedCompare, Memoize, PtrEqWithTypeId, SupportsPtrEqWithTypeId,
 | 
						|
    },
 | 
						|
    module::{ModuleBuilder, NormalModule},
 | 
						|
    source_location::SourceLocation,
 | 
						|
    ty::{
 | 
						|
        CanonicalType, CanonicalTypeKind, CanonicalValue, Connect, DynCanonicalType,
 | 
						|
        DynCanonicalValue, DynType, FixedType, MatchVariantWithoutScope, Type, TypeEnum,
 | 
						|
        TypeWithDeref, Value, ValueEnum,
 | 
						|
    },
 | 
						|
};
 | 
						|
use bitvec::{slice::BitSlice, vec::BitVec};
 | 
						|
use hashbrown::HashMap;
 | 
						|
use std::{
 | 
						|
    fmt,
 | 
						|
    hash::{Hash, Hasher},
 | 
						|
    marker::PhantomData,
 | 
						|
    sync::Arc,
 | 
						|
};
 | 
						|
 | 
						|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
 | 
						|
pub struct FieldType<T> {
 | 
						|
    pub name: Interned<str>,
 | 
						|
    pub flipped: bool,
 | 
						|
    pub ty: T,
 | 
						|
}
 | 
						|
 | 
						|
pub struct FmtDebugInStruct<'a, T> {
 | 
						|
    field: &'a FieldType<T>,
 | 
						|
    field_offset: usize,
 | 
						|
}
 | 
						|
 | 
						|
impl<T: fmt::Debug> fmt::Debug for FmtDebugInStruct<'_, T> {
 | 
						|
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
						|
        let Self {
 | 
						|
            field:
 | 
						|
                &FieldType {
 | 
						|
                    name,
 | 
						|
                    flipped,
 | 
						|
                    ref ty,
 | 
						|
                },
 | 
						|
            field_offset,
 | 
						|
        } = *self;
 | 
						|
        if flipped {
 | 
						|
            write!(f, "#[hdl(flip)] ")?;
 | 
						|
        }
 | 
						|
        if f.alternate() {
 | 
						|
            writeln!(f, "/* offset = {field_offset} */")?;
 | 
						|
        }
 | 
						|
        write!(f, "{name}: ")?;
 | 
						|
        ty.fmt(f)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl<T: fmt::Debug> fmt::Display for FmtDebugInStruct<'_, T> {
 | 
						|
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
						|
        fmt::Debug::fmt(self, f)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl<T> FieldType<T> {
 | 
						|
    pub fn map_ty<U, F: FnOnce(T) -> U>(self, f: F) -> FieldType<U> {
 | 
						|
        let Self { name, flipped, ty } = self;
 | 
						|
        FieldType {
 | 
						|
            name,
 | 
						|
            flipped,
 | 
						|
            ty: f(ty),
 | 
						|
        }
 | 
						|
    }
 | 
						|
    pub fn as_ref_ty(&self) -> FieldType<&T> {
 | 
						|
        FieldType {
 | 
						|
            name: self.name,
 | 
						|
            flipped: self.flipped,
 | 
						|
            ty: &self.ty,
 | 
						|
        }
 | 
						|
    }
 | 
						|
    pub fn fmt_debug_in_struct(&self, field_offset: usize) -> FmtDebugInStruct<'_, T> {
 | 
						|
        FmtDebugInStruct {
 | 
						|
            field: self,
 | 
						|
            field_offset,
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl<T: Type> FieldType<T> {
 | 
						|
    pub fn canonical(&self) -> FieldType<T::CanonicalType> {
 | 
						|
        FieldType {
 | 
						|
            name: self.name,
 | 
						|
            flipped: self.flipped,
 | 
						|
            ty: self.ty.canonical(),
 | 
						|
        }
 | 
						|
    }
 | 
						|
    pub fn to_dyn(&self) -> FieldType<Interned<dyn DynType>> {
 | 
						|
        FieldType {
 | 
						|
            name: self.name,
 | 
						|
            flipped: self.flipped,
 | 
						|
            ty: self.ty.to_dyn(),
 | 
						|
        }
 | 
						|
    }
 | 
						|
    pub fn canonical_dyn(&self) -> FieldType<Interned<dyn DynCanonicalType>> {
 | 
						|
        FieldType {
 | 
						|
            name: self.name,
 | 
						|
            flipped: self.flipped,
 | 
						|
            ty: self.ty.canonical_dyn(),
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl FieldType<Interned<dyn DynCanonicalType>> {
 | 
						|
    pub fn from_canonical_type_helper<T: Type>(
 | 
						|
        self,
 | 
						|
        expected_name: &str,
 | 
						|
        expected_flipped: bool,
 | 
						|
    ) -> T {
 | 
						|
        assert_eq!(&*self.name, expected_name, "field name doesn't match");
 | 
						|
        assert_eq!(
 | 
						|
            self.flipped, expected_flipped,
 | 
						|
            "field {expected_name} orientation (flipped or not) doesn't match"
 | 
						|
        );
 | 
						|
        let ty = &*self.ty;
 | 
						|
        if let Ok(ty) = <dyn DynCanonicalType>::downcast(ty) {
 | 
						|
            return T::from_canonical_type(ty);
 | 
						|
        }
 | 
						|
        let type_name = std::any::type_name::<T::CanonicalType>();
 | 
						|
        panic!("field {expected_name} type doesn't match, expected: {type_name:?}, got: {ty:?}");
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Clone, Eq)]
 | 
						|
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,
 | 
						|
}
 | 
						|
 | 
						|
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])),
 | 
						|
            )
 | 
						|
            .finish()
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl PartialEq for DynBundleTypeImpl {
 | 
						|
    fn eq(&self, other: &Self) -> bool {
 | 
						|
        self.fields == other.fields
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl Hash for DynBundleTypeImpl {
 | 
						|
    fn hash<H: Hasher>(&self, state: &mut H) {
 | 
						|
        self.fields.hash(state);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
 | 
						|
pub struct DynBundleType(Interned<DynBundleTypeImpl>);
 | 
						|
 | 
						|
impl fmt::Debug for DynBundleType {
 | 
						|
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
						|
        self.0.fmt(f)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
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());
 | 
						|
        let mut name_indexes = HashMap::with_capacity(fields.len());
 | 
						|
        let mut field_offsets = Vec::with_capacity(fields.len());
 | 
						|
        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}");
 | 
						|
            }
 | 
						|
            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 {
 | 
						|
                fields,
 | 
						|
                name_indexes,
 | 
						|
                field_offsets: Intern::intern_owned(field_offsets),
 | 
						|
                is_passive,
 | 
						|
                is_storable,
 | 
						|
                is_castable_from_bits,
 | 
						|
                bit_width,
 | 
						|
            }
 | 
						|
            .intern_sized(),
 | 
						|
        )
 | 
						|
    }
 | 
						|
    pub fn is_passive(self) -> bool {
 | 
						|
        self.0.is_passive
 | 
						|
    }
 | 
						|
    pub fn is_storable(self) -> bool {
 | 
						|
        self.0.is_storable
 | 
						|
    }
 | 
						|
    pub fn is_castable_from_bits(self) -> bool {
 | 
						|
        self.0.is_castable_from_bits
 | 
						|
    }
 | 
						|
    pub fn bit_width(self) -> usize {
 | 
						|
        self.0.bit_width
 | 
						|
    }
 | 
						|
    pub fn name_indexes(&self) -> &HashMap<Interned<str>, usize> {
 | 
						|
        &self.0.name_indexes
 | 
						|
    }
 | 
						|
    pub fn field_by_name(
 | 
						|
        &self,
 | 
						|
        name: Interned<str>,
 | 
						|
    ) -> Option<FieldType<Interned<dyn DynCanonicalType>>> {
 | 
						|
        Some(self.0.fields[*self.0.name_indexes.get(&name)?])
 | 
						|
    }
 | 
						|
    pub fn field_offsets(self) -> Interned<[usize]> {
 | 
						|
        self.0.field_offsets
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 | 
						|
pub struct DynBundle {
 | 
						|
    ty: DynBundleType,
 | 
						|
    fields: Arc<[DynCanonicalValue]>,
 | 
						|
}
 | 
						|
 | 
						|
impl DynBundle {
 | 
						|
    pub fn new(ty: DynBundleType, fields: Arc<[DynCanonicalValue]>) -> Self {
 | 
						|
        assert_eq!(
 | 
						|
            ty.fields().len(),
 | 
						|
            fields.len(),
 | 
						|
            "field values don't match type"
 | 
						|
        );
 | 
						|
        for (field_ty, field) in ty.fields().iter().zip(fields.iter()) {
 | 
						|
            assert_eq!(field_ty.ty, field.ty(), "field value doesn't match type");
 | 
						|
        }
 | 
						|
        DynBundle { ty, fields }
 | 
						|
    }
 | 
						|
    pub fn fields(&self) -> &Arc<[DynCanonicalValue]> {
 | 
						|
        &self.fields
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
pub trait TypeHintTrait: Send + Sync + fmt::Debug + SupportsPtrEqWithTypeId {
 | 
						|
    fn matches(&self, ty: &dyn DynType) -> Result<(), String>;
 | 
						|
}
 | 
						|
 | 
						|
impl InternedCompare for dyn TypeHintTrait {
 | 
						|
    type InternedCompareKey = PtrEqWithTypeId;
 | 
						|
    fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey {
 | 
						|
        Self::get_ptr_eq_with_type_id(this)
 | 
						|
    }
 | 
						|
    fn interned_compare_key_weak(this: &std::sync::Weak<Self>) -> Self::InternedCompareKey {
 | 
						|
        Self::get_ptr_eq_with_type_id(&*this.upgrade().unwrap())
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
pub struct TypeHint<T: Type>(PhantomData<fn(T)>);
 | 
						|
 | 
						|
impl<T: Type> TypeHint<T> {
 | 
						|
    pub fn intern_dyn() -> Interned<dyn TypeHintTrait> {
 | 
						|
        Interned::cast_unchecked(
 | 
						|
            Self(PhantomData).intern_sized(),
 | 
						|
            |v| -> &dyn TypeHintTrait { v },
 | 
						|
        )
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl<T: Type> fmt::Debug for TypeHint<T> {
 | 
						|
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
						|
        write!(f, "TypeHint<{}>", std::any::type_name::<T>())
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl<T: Type + Hash> Hash for TypeHint<T> {
 | 
						|
    fn hash<H: Hasher>(&self, _state: &mut H) {}
 | 
						|
}
 | 
						|
 | 
						|
impl<T: Type> Eq for TypeHint<T> {}
 | 
						|
 | 
						|
impl<T: Type> PartialEq for TypeHint<T> {
 | 
						|
    fn eq(&self, _other: &Self) -> bool {
 | 
						|
        true
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl<T: Type> Clone for TypeHint<T> {
 | 
						|
    fn clone(&self) -> Self {
 | 
						|
        *self
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl<T: Type> Copy for TypeHint<T> {}
 | 
						|
 | 
						|
impl<T: Type> TypeHintTrait for TypeHint<T> {
 | 
						|
    fn matches(&self, ty: &dyn DynType) -> Result<(), String> {
 | 
						|
        match ty.downcast::<T>() {
 | 
						|
            Ok(_) => Ok(()),
 | 
						|
            Err(_) => Err(format!("can't cast {ty:?} to {self:?}")),
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
 | 
						|
pub struct FieldsHint {
 | 
						|
    pub known_fields: Interned<[FieldType<Interned<dyn TypeHintTrait>>]>,
 | 
						|
    pub more_fields: bool,
 | 
						|
}
 | 
						|
 | 
						|
impl FieldsHint {
 | 
						|
    pub fn new(
 | 
						|
        known_fields: impl IntoIterator<Item = FieldType<Interned<dyn TypeHintTrait>>>,
 | 
						|
        more_fields: bool,
 | 
						|
    ) -> Self {
 | 
						|
        let known_fields = Intern::intern_owned(Vec::from_iter(known_fields));
 | 
						|
        Self {
 | 
						|
            known_fields,
 | 
						|
            more_fields,
 | 
						|
        }
 | 
						|
    }
 | 
						|
    pub fn check_field(self, index: usize, field: FieldType<&dyn DynType>) -> Result<(), String> {
 | 
						|
        let Some(&known_field) = self.known_fields.get(index) else {
 | 
						|
            return if self.more_fields {
 | 
						|
                Ok(())
 | 
						|
            } else {
 | 
						|
                Err(format!(
 | 
						|
                    "too many fields: name={:?} index={index}",
 | 
						|
                    field.name
 | 
						|
                ))
 | 
						|
            };
 | 
						|
        };
 | 
						|
        let FieldType {
 | 
						|
            name: known_name,
 | 
						|
            flipped: known_flipped,
 | 
						|
            ty: type_hint,
 | 
						|
        } = known_field;
 | 
						|
        let FieldType { name, flipped, ty } = field;
 | 
						|
        if name != known_name {
 | 
						|
            Err(format!(
 | 
						|
                "wrong field name {name:?}, expected {known_name:?}"
 | 
						|
            ))
 | 
						|
        } else if flipped != known_flipped {
 | 
						|
            Err(format!(
 | 
						|
                "wrong field direction: flipped={flipped:?}, expected flipped={known_flipped}"
 | 
						|
            ))
 | 
						|
        } else {
 | 
						|
            type_hint.matches(ty)
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
pub trait BundleType:
 | 
						|
    Type<CanonicalType = DynBundleType, CanonicalValue = DynBundle> + TypeWithDeref + Connect<Self>
 | 
						|
where
 | 
						|
    Self::Value: BundleValue + ToExpr<Type = Self>,
 | 
						|
{
 | 
						|
    type Builder;
 | 
						|
    fn builder() -> Self::Builder;
 | 
						|
    fn fields(&self) -> Interned<[FieldType<Interned<dyn DynCanonicalType>>]>;
 | 
						|
    fn fields_hint() -> FieldsHint;
 | 
						|
}
 | 
						|
 | 
						|
pub trait BundleValue: Value
 | 
						|
where
 | 
						|
    <Self as ToExpr>::Type: BundleType<Value = Self>,
 | 
						|
{
 | 
						|
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
						|
        #[derive(Hash, Eq, PartialEq)]
 | 
						|
        struct ToBitsMemoize<T>(PhantomData<T>);
 | 
						|
        impl<T> Clone for ToBitsMemoize<T> {
 | 
						|
            fn clone(&self) -> Self {
 | 
						|
                *self
 | 
						|
            }
 | 
						|
        }
 | 
						|
        impl<T> Copy for ToBitsMemoize<T> {}
 | 
						|
        impl<T: BundleValue<Type: BundleType<Value = T>>> Memoize for ToBitsMemoize<T> {
 | 
						|
            type Input = T;
 | 
						|
            type InputOwned = T;
 | 
						|
            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());
 | 
						|
                for field in input.fields.iter() {
 | 
						|
                    bits.extend_from_bitslice(&field.to_bits());
 | 
						|
                }
 | 
						|
                Intern::intern_owned(bits)
 | 
						|
            }
 | 
						|
        }
 | 
						|
        ToBitsMemoize::<Self>(PhantomData).get(this)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
pub struct DynBundleMatch;
 | 
						|
 | 
						|
impl Type for DynBundleType {
 | 
						|
    type CanonicalType = DynBundleType;
 | 
						|
    type Value = DynBundle;
 | 
						|
    type CanonicalValue = DynBundle;
 | 
						|
    type MaskType = DynBundleType;
 | 
						|
    type MaskValue = DynBundle;
 | 
						|
    type MatchVariant = DynBundleMatch;
 | 
						|
    type MatchActiveScope = ();
 | 
						|
    type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>;
 | 
						|
    type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>;
 | 
						|
 | 
						|
    fn match_variants<IO: BundleValue>(
 | 
						|
        this: Expr<Self::Value>,
 | 
						|
        module_builder: &mut ModuleBuilder<IO, NormalModule>,
 | 
						|
        source_location: SourceLocation,
 | 
						|
    ) -> Self::MatchVariantsIter
 | 
						|
    where
 | 
						|
        IO::Type: BundleType<Value = IO>,
 | 
						|
    {
 | 
						|
        let _ = this;
 | 
						|
        let _ = module_builder;
 | 
						|
        let _ = source_location;
 | 
						|
        std::iter::once(MatchVariantWithoutScope(DynBundleMatch))
 | 
						|
    }
 | 
						|
 | 
						|
    fn mask_type(&self) -> Self::MaskType {
 | 
						|
        #[derive(Copy, Clone, Eq, PartialEq, Hash)]
 | 
						|
        struct Impl;
 | 
						|
 | 
						|
        impl Memoize for Impl {
 | 
						|
            type Input = DynBundleType;
 | 
						|
            type InputOwned = DynBundleType;
 | 
						|
            type Output = DynBundleType;
 | 
						|
 | 
						|
            fn inner(self, input: &Self::Input) -> Self::Output {
 | 
						|
                DynBundleType::new(Intern::intern_owned(Vec::from_iter(
 | 
						|
                    input
 | 
						|
                        .fields()
 | 
						|
                        .iter()
 | 
						|
                        .map(|&FieldType { name, flipped, ty }| FieldType {
 | 
						|
                            name,
 | 
						|
                            flipped,
 | 
						|
                            ty: ty.mask_type().canonical(),
 | 
						|
                        }),
 | 
						|
                )))
 | 
						|
            }
 | 
						|
        }
 | 
						|
        Impl.get(self)
 | 
						|
    }
 | 
						|
 | 
						|
    fn canonical(&self) -> Self::CanonicalType {
 | 
						|
        *self
 | 
						|
    }
 | 
						|
 | 
						|
    fn source_location(&self) -> SourceLocation {
 | 
						|
        SourceLocation::builtin()
 | 
						|
    }
 | 
						|
 | 
						|
    fn type_enum(&self) -> TypeEnum {
 | 
						|
        TypeEnum::BundleType(*self)
 | 
						|
    }
 | 
						|
 | 
						|
    fn from_canonical_type(t: Self::CanonicalType) -> Self {
 | 
						|
        t
 | 
						|
    }
 | 
						|
 | 
						|
    fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> {
 | 
						|
        Some(this)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
pub struct NoBuilder;
 | 
						|
 | 
						|
impl TypeWithDeref for DynBundleType {
 | 
						|
    fn expr_deref(this: &Expr<Self::Value>) -> &Self::MatchVariant {
 | 
						|
        let _ = this;
 | 
						|
        &DynBundleMatch
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl Connect<Self> for DynBundleType {}
 | 
						|
 | 
						|
impl BundleType for DynBundleType {
 | 
						|
    type Builder = NoBuilder;
 | 
						|
 | 
						|
    fn builder() -> Self::Builder {
 | 
						|
        NoBuilder
 | 
						|
    }
 | 
						|
 | 
						|
    fn fields(&self) -> Interned<[FieldType<Interned<dyn DynCanonicalType>>]> {
 | 
						|
        self.0.fields
 | 
						|
    }
 | 
						|
 | 
						|
    fn fields_hint() -> FieldsHint {
 | 
						|
        FieldsHint {
 | 
						|
            known_fields: [][..].intern(),
 | 
						|
            more_fields: true,
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl CanonicalType for DynBundleType {
 | 
						|
    const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::BundleType;
 | 
						|
}
 | 
						|
 | 
						|
impl ToExpr for DynBundle {
 | 
						|
    type Type = DynBundleType;
 | 
						|
 | 
						|
    fn ty(&self) -> Self::Type {
 | 
						|
        self.ty
 | 
						|
    }
 | 
						|
 | 
						|
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
						|
        Expr::from_value(self)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl Value for DynBundle {
 | 
						|
    fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
 | 
						|
        self.clone()
 | 
						|
    }
 | 
						|
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
						|
        BundleValue::to_bits_impl(this)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl BundleValue for DynBundle {}
 | 
						|
 | 
						|
impl CanonicalValue for DynBundle {
 | 
						|
    fn value_enum_impl(this: &Self) -> ValueEnum {
 | 
						|
        ValueEnum::Bundle(this.clone())
 | 
						|
    }
 | 
						|
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
						|
        BundleValue::to_bits_impl(this)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
macro_rules! impl_tuple_builder {
 | 
						|
    ($builder:ident, [
 | 
						|
        $(($before_Ts:ident $before_fields:ident $before_members:literal))*
 | 
						|
    ] [
 | 
						|
        ($T:ident $field:ident $m:literal)
 | 
						|
        $(($after_Ts:ident $after_fields:ident $after_members:literal))*
 | 
						|
    ]) => {
 | 
						|
        impl_tuple_builder!($builder, [
 | 
						|
            $(($before_Ts $before_fields $before_members))*
 | 
						|
            ($T $field $m)
 | 
						|
        ] [
 | 
						|
            $(($after_Ts $after_fields $after_members))*
 | 
						|
        ]);
 | 
						|
 | 
						|
        impl<Phantom, $($before_Ts,)* $($after_Ts,)*> $builder<Phantom, $($before_Ts,)* () $(, $after_Ts)*> {
 | 
						|
            pub fn $field<$T: ToExpr>(self, $field: $T) -> $builder<Phantom, $($before_Ts,)* Expr<<$T::Type as Type>::Value> $(, $after_Ts)*> {
 | 
						|
                let Self {
 | 
						|
                    $($before_fields,)*
 | 
						|
                    $field: _,
 | 
						|
                    $($after_fields, )*
 | 
						|
                    _phantom: _,
 | 
						|
                } = self;
 | 
						|
                let $field = $field.to_expr();
 | 
						|
                $builder {
 | 
						|
                    $($before_fields,)*
 | 
						|
                    $field,
 | 
						|
                    $($after_fields,)*
 | 
						|
                    _phantom: PhantomData,
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    };
 | 
						|
    ($builder:ident, [$($before:tt)*] []) => {};
 | 
						|
}
 | 
						|
 | 
						|
macro_rules! into_unit {
 | 
						|
    ($($tt:tt)*) => {
 | 
						|
        ()
 | 
						|
    };
 | 
						|
}
 | 
						|
 | 
						|
macro_rules! impl_tuple {
 | 
						|
    ($builder:ident, $(($T:ident $T2:ident $field:ident $m:tt)),*) => {
 | 
						|
        pub struct $builder<Phantom, $($T),*> {
 | 
						|
            $($field: $T,)*
 | 
						|
            _phantom: PhantomData<Phantom>,
 | 
						|
        }
 | 
						|
 | 
						|
        impl_tuple_builder!($builder, [] [$(($T $field $m))*]);
 | 
						|
 | 
						|
        impl<$($T: Value),*> $builder<($($T,)*), $(Expr<$T>,)*>
 | 
						|
        where
 | 
						|
            $($T::Type: Type<Value = $T>,)*
 | 
						|
        {
 | 
						|
            pub fn build(self) -> Expr<($($T,)*)> {
 | 
						|
                let Self {
 | 
						|
                    $($field,)*
 | 
						|
                    _phantom: _,
 | 
						|
                } = self;
 | 
						|
                BundleLiteral::new_unchecked(
 | 
						|
                    [$($field.to_canonical_dyn()),*][..].intern(),
 | 
						|
                    ($($field.ty(),)*),
 | 
						|
                ).to_expr()
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        impl<$($T: ToExpr,)*> ToExpr for ($($T,)*) {
 | 
						|
            type Type = ($($T::Type,)*);
 | 
						|
 | 
						|
            #[allow(clippy::unused_unit)]
 | 
						|
            fn ty(&self) -> Self::Type {
 | 
						|
                let ($($field,)*) = self;
 | 
						|
                ($($field.ty(),)*)
 | 
						|
            }
 | 
						|
 | 
						|
            fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
						|
                let ($($field,)*) = self;
 | 
						|
                $(let $field = $field.to_expr();)*
 | 
						|
                BundleLiteral::new_unchecked(
 | 
						|
                    [$($field.to_canonical_dyn()),*][..].intern(),
 | 
						|
                    ($($field.ty(),)*),
 | 
						|
                ).to_expr()
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        impl<$($T, $T2,)*> Connect<($($T2,)*)> for ($($T,)*)
 | 
						|
        where
 | 
						|
            $($T: Connect<$T2>,)*
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
        impl<$($T: Type,)*> Type for ($($T,)*)
 | 
						|
        where
 | 
						|
            $($T::Value: Value<Type = $T>,)*
 | 
						|
        {
 | 
						|
            type CanonicalType = DynBundleType;
 | 
						|
            type Value = ($($T::Value,)*);
 | 
						|
            type CanonicalValue = DynBundle;
 | 
						|
            type MaskType = ($($T::MaskType,)*);
 | 
						|
            type MaskValue = ($($T::MaskValue,)*);
 | 
						|
            type MatchVariant = ($(Expr<$T::Value>,)*);
 | 
						|
            type MatchActiveScope = ();
 | 
						|
            type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>;
 | 
						|
            type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>;
 | 
						|
 | 
						|
            fn match_variants<IO: BundleValue>(
 | 
						|
                this: Expr<Self::Value>,
 | 
						|
                module_builder: &mut ModuleBuilder<IO, NormalModule>,
 | 
						|
                source_location: SourceLocation,
 | 
						|
            ) -> Self::MatchVariantsIter
 | 
						|
            where
 | 
						|
                IO::Type: BundleType<Value = IO>,
 | 
						|
            {
 | 
						|
                let _ = this;
 | 
						|
                let _ = module_builder;
 | 
						|
                let _ = source_location;
 | 
						|
                std::iter::once(MatchVariantWithoutScope(($(this.field(stringify!($m)),)*)))
 | 
						|
            }
 | 
						|
 | 
						|
            #[allow(clippy::unused_unit)]
 | 
						|
            fn mask_type(&self) -> Self::MaskType {
 | 
						|
                let ($($field,)*) = self;
 | 
						|
                ($($field.mask_type(),)*)
 | 
						|
            }
 | 
						|
 | 
						|
            fn canonical(&self) -> Self::CanonicalType {
 | 
						|
                DynBundleType::new(self.fields())
 | 
						|
            }
 | 
						|
 | 
						|
            fn source_location(&self) -> SourceLocation {
 | 
						|
                SourceLocation::builtin()
 | 
						|
            }
 | 
						|
 | 
						|
            fn type_enum(&self) -> TypeEnum {
 | 
						|
                TypeEnum::BundleType(self.canonical())
 | 
						|
            }
 | 
						|
 | 
						|
            #[allow(clippy::unused_unit)]
 | 
						|
            fn from_canonical_type(t: Self::CanonicalType) -> Self {
 | 
						|
                let [$($field),*] = *t.fields() else {
 | 
						|
                    panic!("wrong number of fields");
 | 
						|
                };
 | 
						|
                ($($field.from_canonical_type_helper(stringify!($m), false),)*)
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        impl<$($T: Type,)*> TypeWithDeref for ($($T,)*)
 | 
						|
        where
 | 
						|
            $($T::Value: Value<Type = $T>,)*
 | 
						|
        {
 | 
						|
            fn expr_deref(
 | 
						|
                this: &::fayalite::expr::Expr<<Self as ::fayalite::ty::Type>::Value>,
 | 
						|
            ) -> &<Self as ::fayalite::ty::Type>::MatchVariant {
 | 
						|
                let _ = this;
 | 
						|
                Interned::<_>::into_inner(
 | 
						|
                    Intern::intern_sized((
 | 
						|
                        $(this.field(stringify!($m)),)*
 | 
						|
                    )),
 | 
						|
                )
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        impl<$($T: Type,)*> BundleType for ($($T,)*)
 | 
						|
        where
 | 
						|
            $($T::Value: Value<Type = $T>,)*
 | 
						|
        {
 | 
						|
            type Builder = $builder<($($T::Value,)*), $(into_unit!($T),)*>;
 | 
						|
            fn builder() -> Self::Builder {
 | 
						|
                $builder {
 | 
						|
                    $($field: (),)*
 | 
						|
                    _phantom: PhantomData,
 | 
						|
                }
 | 
						|
            }
 | 
						|
            fn fields(
 | 
						|
                &self,
 | 
						|
            ) -> Interned<[FieldType<Interned<dyn DynCanonicalType>>]> {
 | 
						|
                [
 | 
						|
                    $(FieldType {
 | 
						|
                        name: stringify!($m).intern(),
 | 
						|
                        flipped: false,
 | 
						|
                        ty: self.$m.canonical_dyn(),
 | 
						|
                    },)*
 | 
						|
                ][..].intern()
 | 
						|
            }
 | 
						|
            fn fields_hint() -> FieldsHint {
 | 
						|
                FieldsHint::new([
 | 
						|
                    $(FieldType {
 | 
						|
                        name: stringify!($m).intern(),
 | 
						|
                        flipped: false,
 | 
						|
                        ty: TypeHint::<$T>::intern_dyn(),
 | 
						|
                    },)*
 | 
						|
                ], false)
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        impl<$($T: FixedType,)*> FixedType for ($($T,)*)
 | 
						|
        where
 | 
						|
            $($T::Value: Value<Type = $T>,)*
 | 
						|
        {
 | 
						|
            #[allow(clippy::unused_unit)]
 | 
						|
            fn fixed_type() -> Self {
 | 
						|
                ($($T::fixed_type(),)*)
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        impl<$($T: Value,)*> Value for ($($T,)*)
 | 
						|
        where
 | 
						|
            $($T::Type: Type<Value = $T>,)*
 | 
						|
        {
 | 
						|
            fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
 | 
						|
                let ty = self.ty().canonical();
 | 
						|
                DynBundle::new(
 | 
						|
                    ty,
 | 
						|
                    Arc::new([
 | 
						|
                        $(self.$m.to_canonical_dyn(),)*
 | 
						|
                    ]),
 | 
						|
                )
 | 
						|
            }
 | 
						|
            fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
						|
                BundleValue::to_bits_impl(this)
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        impl<$($T: Value,)*> BundleValue for ($($T,)*)
 | 
						|
        where
 | 
						|
            $($T::Type: Type<Value = $T>,)*
 | 
						|
        {
 | 
						|
        }
 | 
						|
    };
 | 
						|
}
 | 
						|
 | 
						|
impl_tuple!(TupleBuilder0,);
 | 
						|
impl_tuple!(TupleBuilder1, (A A2 field_0 0));
 | 
						|
impl_tuple!(TupleBuilder2, (A A2 field_0 0), (B B2 field_1 1));
 | 
						|
impl_tuple!(TupleBuilder3, (A A2 field_0 0), (B B2 field_1 1), (C C2 field_2 2));
 | 
						|
impl_tuple!(TupleBuilder4, (A A2 field_0 0), (B B2 field_1 1), (C C2 field_2 2), (D D2 field_3 3));
 | 
						|
impl_tuple!(TupleBuilder5, (A A2 field_0 0), (B B2 field_1 1), (C C2 field_2 2), (D D2 field_3 3), (E E2 field_4 4));
 | 
						|
impl_tuple!(TupleBuilder6, (A A2 field_0 0), (B B2 field_1 1), (C C2 field_2 2), (D D2 field_3 3), (E E2 field_4 4), (F F2 field_5 5));
 | 
						|
impl_tuple!(TupleBuilder7, (A A2 field_0 0), (B B2 field_1 1), (C C2 field_2 2), (D D2 field_3 3), (E E2 field_4 4), (F F2 field_5 5), (G G2 field_6 6));
 | 
						|
impl_tuple!(TupleBuilder8, (A A2 field_0 0), (B B2 field_1 1), (C C2 field_2 2), (D D2 field_3 3), (E E2 field_4 4), (F F2 field_5 5), (G G2 field_6 6), (H H2 field_7 7));
 | 
						|
impl_tuple!(TupleBuilder9, (A A2 field_0 0), (B B2 field_1 1), (C C2 field_2 2), (D D2 field_3 3), (E E2 field_4 4), (F F2 field_5 5), (G G2 field_6 6), (H H2 field_7 7), (I I2 field_8 8));
 | 
						|
impl_tuple!(TupleBuilder10, (A A2 field_0 0), (B B2 field_1 1), (C C2 field_2 2), (D D2 field_3 3), (E E2 field_4 4), (F F2 field_5 5), (G G2 field_6 6), (H H2 field_7 7), (I I2 field_8 8), (J J2 field_9 9));
 | 
						|
impl_tuple!(TupleBuilder11, (A A2 field_0 0), (B B2 field_1 1), (C C2 field_2 2), (D D2 field_3 3), (E E2 field_4 4), (F F2 field_5 5), (G G2 field_6 6), (H H2 field_7 7), (I I2 field_8 8), (J J2 field_9 9), (K K2 field_10 10));
 | 
						|
impl_tuple!(TupleBuilder12, (A A2 field_0 0), (B B2 field_1 1), (C C2 field_2 2), (D D2 field_3 3), (E E2 field_4 4), (F F2 field_5 5), (G G2 field_6 6), (H H2 field_7 7), (I I2 field_8 8), (J J2 field_9 9), (K K2 field_10 10), (L L2 field_11 11));
 |