Compare commits
	
		
			2 commits
		
	
	
		
			bd75fdfefd
			...
			c0c5b550bc
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c0c5b550bc | |||
| 2fa0ea6192 | 
					 15 changed files with 446 additions and 16 deletions
				
			
		| 
						 | 
				
			
			@ -16,6 +16,7 @@ use crate::{
 | 
			
		|||
        transform::visit::{Fold, Folder, Visit, Visitor},
 | 
			
		||||
        Instance, ModuleIO,
 | 
			
		||||
    },
 | 
			
		||||
    phantom_const::PhantomConst,
 | 
			
		||||
    reg::Reg,
 | 
			
		||||
    reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
 | 
			
		||||
    ty::{CanonicalType, StaticType, Type, TypeWithDeref},
 | 
			
		||||
| 
						 | 
				
			
			@ -109,6 +110,7 @@ expr_enum! {
 | 
			
		|||
        UIntLiteral(Interned<UIntValue>),
 | 
			
		||||
        SIntLiteral(Interned<SIntValue>),
 | 
			
		||||
        BoolLiteral(bool),
 | 
			
		||||
        PhantomConst(PhantomConst),
 | 
			
		||||
        BundleLiteral(ops::BundleLiteral),
 | 
			
		||||
        ArrayLiteral(ops::ArrayLiteral<CanonicalType, DynSize>),
 | 
			
		||||
        EnumLiteral(ops::EnumLiteral),
 | 
			
		||||
| 
						 | 
				
			
			@ -755,3 +757,27 @@ pub fn repeat<T: Type, L: SizeType>(
 | 
			
		|||
    )
 | 
			
		||||
    .to_expr()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> ToExpr for PhantomConst<T> {
 | 
			
		||||
    type Type = Self;
 | 
			
		||||
 | 
			
		||||
    fn to_expr(&self) -> Expr<Self::Type> {
 | 
			
		||||
        Expr {
 | 
			
		||||
            __enum: ExprEnum::PhantomConst(self.canonical_phantom_const()).intern_sized(),
 | 
			
		||||
            __ty: *self,
 | 
			
		||||
            __flow: Flow::Source,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> GetTarget for PhantomConst<T> {
 | 
			
		||||
    fn target(&self) -> Option<Interned<Target>> {
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> ToLiteralBits for PhantomConst<T> {
 | 
			
		||||
    fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
 | 
			
		||||
        Ok(Interned::default())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,14 +11,15 @@ use crate::{
 | 
			
		|||
            GetTarget, Target, TargetPathArrayElement, TargetPathBundleField,
 | 
			
		||||
            TargetPathDynArrayElement, TargetPathElement,
 | 
			
		||||
        },
 | 
			
		||||
        CastTo, Expr, ExprEnum, Flow, HdlPartialEq, HdlPartialOrd, NotALiteralExpr, ReduceBits,
 | 
			
		||||
        ToExpr, ToLiteralBits,
 | 
			
		||||
        CastBitsTo as _, CastTo, CastToBits as _, Expr, ExprEnum, Flow, HdlPartialEq,
 | 
			
		||||
        HdlPartialOrd, NotALiteralExpr, ReduceBits, ToExpr, ToLiteralBits,
 | 
			
		||||
    },
 | 
			
		||||
    int::{
 | 
			
		||||
        Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
 | 
			
		||||
        UIntType, UIntValue,
 | 
			
		||||
    },
 | 
			
		||||
    intern::{Intern, Interned},
 | 
			
		||||
    phantom_const::{PhantomConst, PhantomConstValue},
 | 
			
		||||
    reset::{
 | 
			
		||||
        AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
 | 
			
		||||
        ToSyncReset,
 | 
			
		||||
| 
						 | 
				
			
			@ -1892,6 +1893,26 @@ impl ExprCastTo<Clock> for Clock {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> ExprCastTo<()> for PhantomConst<T> {
 | 
			
		||||
    fn cast_to(src: Expr<Self>, to_type: ()) -> Expr<()> {
 | 
			
		||||
        src.cast_to_bits().cast_bits_to(to_type)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> ExprCastTo<PhantomConst<T>> for () {
 | 
			
		||||
    fn cast_to(src: Expr<Self>, to_type: PhantomConst<T>) -> Expr<PhantomConst<T>> {
 | 
			
		||||
        src.cast_to_bits().cast_bits_to(to_type)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue, U: ?Sized + PhantomConstValue> ExprCastTo<PhantomConst<T>>
 | 
			
		||||
    for PhantomConst<U>
 | 
			
		||||
{
 | 
			
		||||
    fn cast_to(src: Expr<Self>, to_type: PhantomConst<T>) -> Expr<PhantomConst<T>> {
 | 
			
		||||
        src.cast_to_bits().cast_bits_to(to_type)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 | 
			
		||||
pub struct FieldAccess<FieldType: Type = CanonicalType> {
 | 
			
		||||
    base: Expr<Bundle>,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ use crate::{
 | 
			
		|||
        target::{
 | 
			
		||||
            Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement,
 | 
			
		||||
        },
 | 
			
		||||
        Expr, ExprEnum,
 | 
			
		||||
        CastBitsTo, Expr, ExprEnum,
 | 
			
		||||
    },
 | 
			
		||||
    formal::FormalKind,
 | 
			
		||||
    int::{Bool, DynSize, IntType, SIntValue, UInt, UIntValue},
 | 
			
		||||
| 
						 | 
				
			
			@ -447,6 +447,7 @@ impl TypeState {
 | 
			
		|||
            CanonicalType::AsyncReset(AsyncReset {}) => "AsyncReset".into(),
 | 
			
		||||
            CanonicalType::SyncReset(SyncReset {}) => "UInt<1>".into(),
 | 
			
		||||
            CanonicalType::Reset(Reset {}) => "Reset".into(),
 | 
			
		||||
            CanonicalType::PhantomConst(_) => "{}".into(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1152,6 +1153,7 @@ impl<'a> Exporter<'a> {
 | 
			
		|||
            | CanonicalType::Clock(_)
 | 
			
		||||
            | CanonicalType::AsyncReset(_)
 | 
			
		||||
            | CanonicalType::Reset(_) => format!("asUInt({value_str})"),
 | 
			
		||||
            CanonicalType::PhantomConst(_) => "UInt<0>(0)".into(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn expr_cast_bits_to_bundle(
 | 
			
		||||
| 
						 | 
				
			
			@ -1357,6 +1359,12 @@ impl<'a> Exporter<'a> {
 | 
			
		|||
            CanonicalType::AsyncReset(_) => format!("asAsyncReset({value_str})"),
 | 
			
		||||
            CanonicalType::SyncReset(_) => value_str,
 | 
			
		||||
            CanonicalType::Reset(_) => unreachable!("Reset is not bit castable to"),
 | 
			
		||||
            CanonicalType::PhantomConst(_) => {
 | 
			
		||||
                let retval = self.module.ns.make_new("_cast_bits_to_phantom_const_expr");
 | 
			
		||||
                definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {{}}"));
 | 
			
		||||
                definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}"));
 | 
			
		||||
                return retval.to_string();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn expr_unary<T: Type>(
 | 
			
		||||
| 
						 | 
				
			
			@ -1395,6 +1403,11 @@ impl<'a> Exporter<'a> {
 | 
			
		|||
            ExprEnum::UIntLiteral(literal) => self.uint_literal(&literal),
 | 
			
		||||
            ExprEnum::SIntLiteral(literal) => self.sint_literal(&literal),
 | 
			
		||||
            ExprEnum::BoolLiteral(literal) => self.bool_literal(literal),
 | 
			
		||||
            ExprEnum::PhantomConst(ty) => self.expr(
 | 
			
		||||
                UInt[0].zero().cast_bits_to(ty.canonical()),
 | 
			
		||||
                definitions,
 | 
			
		||||
                const_ty,
 | 
			
		||||
            ),
 | 
			
		||||
            ExprEnum::ArrayLiteral(array_literal) => {
 | 
			
		||||
                self.array_literal_expr(array_literal, definitions, const_ty)
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,6 +96,7 @@ pub mod int;
 | 
			
		|||
pub mod intern;
 | 
			
		||||
pub mod memory;
 | 
			
		||||
pub mod module;
 | 
			
		||||
pub mod phantom_const;
 | 
			
		||||
pub mod prelude;
 | 
			
		||||
pub mod reg;
 | 
			
		||||
pub mod reset;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1082,6 +1082,7 @@ pub fn splat_mask<T: Type>(ty: T, value: Expr<Bool>) -> Expr<AsMask<T>> {
 | 
			
		|||
            )
 | 
			
		||||
            .to_expr(),
 | 
			
		||||
        )),
 | 
			
		||||
        CanonicalType::PhantomConst(_) => Expr::from_canonical(Expr::canonical(().to_expr())),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1490,6 +1490,9 @@ impl TargetState {
 | 
			
		|||
                        })
 | 
			
		||||
                        .collect(),
 | 
			
		||||
                },
 | 
			
		||||
                CanonicalType::PhantomConst(_) => TargetStateInner::Decomposed {
 | 
			
		||||
                    subtargets: HashMap::new(),
 | 
			
		||||
                },
 | 
			
		||||
                CanonicalType::Array(ty) => TargetStateInner::Decomposed {
 | 
			
		||||
                    subtargets: (0..ty.len())
 | 
			
		||||
                        .map(|index| {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,6 +155,7 @@ impl ResetsLayout {
 | 
			
		|||
                    CanonicalType::SyncReset(_) => ResetsLayout::SyncReset,
 | 
			
		||||
                    CanonicalType::Reset(_) => ResetsLayout::Reset,
 | 
			
		||||
                    CanonicalType::Clock(_) => ResetsLayout::NoResets,
 | 
			
		||||
                    CanonicalType::PhantomConst(_) => ResetsLayout::NoResets,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -407,7 +408,8 @@ impl Resets {
 | 
			
		|||
            | CanonicalType::Bool(_)
 | 
			
		||||
            | CanonicalType::AsyncReset(_)
 | 
			
		||||
            | CanonicalType::SyncReset(_)
 | 
			
		||||
            | CanonicalType::Clock(_) => Ok(self.ty),
 | 
			
		||||
            | CanonicalType::Clock(_)
 | 
			
		||||
            | CanonicalType::PhantomConst(_) => Ok(self.ty),
 | 
			
		||||
            CanonicalType::Array(ty) => Ok(CanonicalType::Array(Array::new_dyn(
 | 
			
		||||
                self.array_elements().substituted_type(
 | 
			
		||||
                    reset_graph,
 | 
			
		||||
| 
						 | 
				
			
			@ -998,7 +1000,8 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
 | 
			
		|||
                            CanonicalType::Array(_)
 | 
			
		||||
                            | CanonicalType::Enum(_)
 | 
			
		||||
                            | CanonicalType::Bundle(_)
 | 
			
		||||
                            | CanonicalType::Reset(_) => unreachable!(),
 | 
			
		||||
                            | CanonicalType::Reset(_)
 | 
			
		||||
                            | CanonicalType::PhantomConst(_) => unreachable!(),
 | 
			
		||||
                            $(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)*
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
| 
						 | 
				
			
			@ -1010,6 +1013,7 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
 | 
			
		|||
                            | CanonicalType::Enum(_)
 | 
			
		||||
                            | CanonicalType::Bundle(_)
 | 
			
		||||
                            | CanonicalType::Reset(_) => unreachable!(),
 | 
			
		||||
                            CanonicalType::PhantomConst(_) => Expr::expr_enum(arg),
 | 
			
		||||
                            $(CanonicalType::$Variant(_) => {
 | 
			
		||||
                                let arg = Expr::<$Variant>::from_canonical(arg);
 | 
			
		||||
                                match_expr_ty!(arg, UInt, SInt, Bool, AsyncReset, SyncReset, Clock)
 | 
			
		||||
| 
						 | 
				
			
			@ -1040,6 +1044,7 @@ impl<P: Pass> RunPass<P> for ExprEnum {
 | 
			
		|||
            ExprEnum::UIntLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
 | 
			
		||||
            ExprEnum::SIntLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
 | 
			
		||||
            ExprEnum::BoolLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
 | 
			
		||||
            ExprEnum::PhantomConst(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
 | 
			
		||||
            ExprEnum::BundleLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
 | 
			
		||||
            ExprEnum::ArrayLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
 | 
			
		||||
            ExprEnum::EnumLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
 | 
			
		||||
| 
						 | 
				
			
			@ -1670,7 +1675,8 @@ impl RunPassDispatch for AnyReg {
 | 
			
		|||
                | CanonicalType::Enum(_)
 | 
			
		||||
                | CanonicalType::Bundle(_)
 | 
			
		||||
                | CanonicalType::Reset(_)
 | 
			
		||||
                | CanonicalType::Clock(_) => unreachable!(),
 | 
			
		||||
                | CanonicalType::Clock(_)
 | 
			
		||||
                | CanonicalType::PhantomConst(_) => unreachable!(),
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1769,6 +1775,7 @@ impl_run_pass_copy!([] SVAttributeAnnotation);
 | 
			
		|||
impl_run_pass_copy!([] UInt);
 | 
			
		||||
impl_run_pass_copy!([] usize);
 | 
			
		||||
impl_run_pass_copy!([] FormalKind);
 | 
			
		||||
impl_run_pass_copy!([] PhantomConst);
 | 
			
		||||
 | 
			
		||||
macro_rules! impl_run_pass_for_struct {
 | 
			
		||||
    (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,7 +69,8 @@ fn contains_any_enum_types(ty: CanonicalType) -> bool {
 | 
			
		|||
                | CanonicalType::AsyncReset(_)
 | 
			
		||||
                | CanonicalType::SyncReset(_)
 | 
			
		||||
                | CanonicalType::Reset(_)
 | 
			
		||||
                | CanonicalType::Clock(_) => false,
 | 
			
		||||
                | CanonicalType::Clock(_)
 | 
			
		||||
                | CanonicalType::PhantomConst(_) => false,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -512,7 +513,8 @@ impl State {
 | 
			
		|||
            | CanonicalType::AsyncReset(_)
 | 
			
		||||
            | CanonicalType::SyncReset(_)
 | 
			
		||||
            | CanonicalType::Reset(_)
 | 
			
		||||
            | CanonicalType::Clock(_) => unreachable!(),
 | 
			
		||||
            | CanonicalType::Clock(_)
 | 
			
		||||
            | CanonicalType::PhantomConst(_) => unreachable!(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -577,7 +579,8 @@ fn connect_port(
 | 
			
		|||
        | (CanonicalType::Clock(_), _)
 | 
			
		||||
        | (CanonicalType::AsyncReset(_), _)
 | 
			
		||||
        | (CanonicalType::SyncReset(_), _)
 | 
			
		||||
        | (CanonicalType::Reset(_), _) => unreachable!(
 | 
			
		||||
        | (CanonicalType::Reset(_), _)
 | 
			
		||||
        | (CanonicalType::PhantomConst(_), _) => unreachable!(
 | 
			
		||||
            "trying to connect memory ports:\n{:?}\n{:?}",
 | 
			
		||||
            Expr::ty(lhs),
 | 
			
		||||
            Expr::ty(rhs),
 | 
			
		||||
| 
						 | 
				
			
			@ -665,6 +668,7 @@ impl Folder for State {
 | 
			
		|||
            ExprEnum::UIntLiteral(_)
 | 
			
		||||
            | ExprEnum::SIntLiteral(_)
 | 
			
		||||
            | ExprEnum::BoolLiteral(_)
 | 
			
		||||
            | ExprEnum::PhantomConst(_)
 | 
			
		||||
            | ExprEnum::BundleLiteral(_)
 | 
			
		||||
            | ExprEnum::ArrayLiteral(_)
 | 
			
		||||
            | ExprEnum::Uninit(_)
 | 
			
		||||
| 
						 | 
				
			
			@ -923,7 +927,8 @@ impl Folder for State {
 | 
			
		|||
            | CanonicalType::Clock(_)
 | 
			
		||||
            | CanonicalType::AsyncReset(_)
 | 
			
		||||
            | CanonicalType::SyncReset(_)
 | 
			
		||||
            | CanonicalType::Reset(_) => canonical_type.default_fold(self),
 | 
			
		||||
            | CanonicalType::Reset(_)
 | 
			
		||||
            | CanonicalType::PhantomConst(_) => canonical_type.default_fold(self),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,6 +62,7 @@ enum MemSplit {
 | 
			
		|||
    Bundle {
 | 
			
		||||
        fields: Rc<[MemSplit]>,
 | 
			
		||||
    },
 | 
			
		||||
    PhantomConst,
 | 
			
		||||
    Single {
 | 
			
		||||
        output_mem: Option<Mem>,
 | 
			
		||||
        element_type: SingleType,
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +77,7 @@ impl MemSplit {
 | 
			
		|||
    fn mark_changed_element_type(self) -> Self {
 | 
			
		||||
        match self {
 | 
			
		||||
            MemSplit::Bundle { fields: _ } => self,
 | 
			
		||||
            MemSplit::PhantomConst => self,
 | 
			
		||||
            MemSplit::Single {
 | 
			
		||||
                output_mem,
 | 
			
		||||
                element_type,
 | 
			
		||||
| 
						 | 
				
			
			@ -97,6 +99,7 @@ impl MemSplit {
 | 
			
		|||
                    .map(|field| Self::new(field.ty).mark_changed_element_type())
 | 
			
		||||
                    .collect(),
 | 
			
		||||
            },
 | 
			
		||||
            CanonicalType::PhantomConst(_) => MemSplit::PhantomConst,
 | 
			
		||||
            CanonicalType::Array(ty) => {
 | 
			
		||||
                let element = MemSplit::new(ty.element());
 | 
			
		||||
                if let Self::Single {
 | 
			
		||||
| 
						 | 
				
			
			@ -339,6 +342,7 @@ impl SplitMemState<'_, '_> {
 | 
			
		|||
                    self.split_state_stack.pop();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            MemSplit::PhantomConst => {}
 | 
			
		||||
            MemSplit::Single {
 | 
			
		||||
                output_mem,
 | 
			
		||||
                element_type: single_type,
 | 
			
		||||
| 
						 | 
				
			
			@ -538,7 +542,12 @@ impl ModuleState {
 | 
			
		|||
            };
 | 
			
		||||
        loop {
 | 
			
		||||
            match input_element_type {
 | 
			
		||||
                CanonicalType::Bundle(_) => unreachable!("bundle types are always split"),
 | 
			
		||||
                CanonicalType::Bundle(_) => {
 | 
			
		||||
                    unreachable!("bundle types are always split")
 | 
			
		||||
                }
 | 
			
		||||
                CanonicalType::PhantomConst(_) => {
 | 
			
		||||
                    unreachable!("PhantomConst are always removed")
 | 
			
		||||
                }
 | 
			
		||||
                CanonicalType::Enum(_)
 | 
			
		||||
                    if input_array_types
 | 
			
		||||
                        .first()
 | 
			
		||||
| 
						 | 
				
			
			@ -743,7 +752,8 @@ impl ModuleState {
 | 
			
		|||
                ..
 | 
			
		||||
            }
 | 
			
		||||
            | MemSplit::Bundle { .. }
 | 
			
		||||
            | MemSplit::Array { .. } => {
 | 
			
		||||
            | MemSplit::Array { .. }
 | 
			
		||||
            | MemSplit::PhantomConst => {
 | 
			
		||||
                let mut replacement_ports = Vec::with_capacity(input_mem.ports().len());
 | 
			
		||||
                let mut wire_port_rdata = Vec::with_capacity(input_mem.ports().len());
 | 
			
		||||
                let mut wire_port_wdata = Vec::with_capacity(input_mem.ports().len());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,7 @@ use crate::{
 | 
			
		|||
        NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf,
 | 
			
		||||
        StmtInstance, StmtMatch, StmtReg, StmtWire,
 | 
			
		||||
    },
 | 
			
		||||
    phantom_const::PhantomConst,
 | 
			
		||||
    reg::Reg,
 | 
			
		||||
    reset::{AsyncReset, Reset, ResetType, SyncReset},
 | 
			
		||||
    source_location::SourceLocation,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										273
									
								
								crates/fayalite/src/phantom_const.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								crates/fayalite/src/phantom_const.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,273 @@
 | 
			
		|||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
			
		||||
// See Notices.txt for copyright information
 | 
			
		||||
 | 
			
		||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    intern::{Intern, Interned, InternedCompare, LazyInterned, Memoize},
 | 
			
		||||
    source_location::SourceLocation,
 | 
			
		||||
    ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
 | 
			
		||||
};
 | 
			
		||||
use std::{
 | 
			
		||||
    any::Any,
 | 
			
		||||
    fmt,
 | 
			
		||||
    hash::{Hash, Hasher},
 | 
			
		||||
    marker::PhantomData,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct PhantomConstCanonicalValue {
 | 
			
		||||
    parsed: serde_json::Value,
 | 
			
		||||
    serialized: Interned<str>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PhantomConstCanonicalValue {
 | 
			
		||||
    pub fn from_json_value(parsed: serde_json::Value) -> Self {
 | 
			
		||||
        let serialized = Intern::intern_owned(
 | 
			
		||||
            serde_json::to_string(&parsed)
 | 
			
		||||
                .expect("conversion from json value to text shouldn't fail"),
 | 
			
		||||
        );
 | 
			
		||||
        Self { parsed, serialized }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn as_json_value(&self) -> &serde_json::Value {
 | 
			
		||||
        &self.parsed
 | 
			
		||||
    }
 | 
			
		||||
    pub fn as_str(&self) -> Interned<str> {
 | 
			
		||||
        self.serialized
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Debug for PhantomConstCanonicalValue {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        f.write_str(&self.serialized)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for PhantomConstCanonicalValue {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        f.write_str(&self.serialized)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PartialEq for PhantomConstCanonicalValue {
 | 
			
		||||
    fn eq(&self, other: &Self) -> bool {
 | 
			
		||||
        self.serialized == other.serialized
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Eq for PhantomConstCanonicalValue {}
 | 
			
		||||
 | 
			
		||||
impl Hash for PhantomConstCanonicalValue {
 | 
			
		||||
    fn hash<H: Hasher>(&self, state: &mut H) {
 | 
			
		||||
        self.serialized.hash(state);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Serialize for PhantomConstCanonicalValue {
 | 
			
		||||
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 | 
			
		||||
    where
 | 
			
		||||
        S: serde::Serializer,
 | 
			
		||||
    {
 | 
			
		||||
        self.parsed.serialize(serializer)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'de> Deserialize<'de> for PhantomConstCanonicalValue {
 | 
			
		||||
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
 | 
			
		||||
    where
 | 
			
		||||
        D: serde::Deserializer<'de>,
 | 
			
		||||
    {
 | 
			
		||||
        Ok(Self::from_json_value(serde_json::Value::deserialize(
 | 
			
		||||
            deserializer,
 | 
			
		||||
        )?))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait PhantomConstValue: Intern + InternedCompare + Serialize + fmt::Debug {
 | 
			
		||||
    fn deserialize<'de, D>(deserializer: D) -> Result<Interned<Self>, D::Error>
 | 
			
		||||
    where
 | 
			
		||||
        D: serde::Deserializer<'de>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> PhantomConstValue for T
 | 
			
		||||
where
 | 
			
		||||
    T: ?Sized + Intern + InternedCompare + Serialize + fmt::Debug,
 | 
			
		||||
    Interned<T>: DeserializeOwned,
 | 
			
		||||
{
 | 
			
		||||
    fn deserialize<'de, D>(deserializer: D) -> Result<Interned<Self>, D::Error>
 | 
			
		||||
    where
 | 
			
		||||
        D: serde::Deserializer<'de>,
 | 
			
		||||
    {
 | 
			
		||||
        <Interned<T> as Deserialize<'de>>::deserialize(deserializer)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Wrapper type that allows any Rust value to be smuggled as a HDL [`Type`].
 | 
			
		||||
/// This only works for values that can be [serialized][Serialize] to and [deserialized][Deserialize] from [JSON][serde_json].
 | 
			
		||||
pub struct PhantomConst<T: ?Sized + PhantomConstValue = PhantomConstCanonicalValue> {
 | 
			
		||||
    value: LazyInterned<T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> fmt::Debug for PhantomConst<T> {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        f.debug_tuple("PhantomConst").field(&self.get()).finish()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> Clone for PhantomConst<T> {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> Copy for PhantomConst<T> {}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> PartialEq for PhantomConst<T> {
 | 
			
		||||
    fn eq(&self, other: &Self) -> bool {
 | 
			
		||||
        self.get() == other.get()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> Eq for PhantomConst<T> {}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> Hash for PhantomConst<T> {
 | 
			
		||||
    fn hash<H: Hasher>(&self, state: &mut H) {
 | 
			
		||||
        self.get().hash(state);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct PhantomConstCanonicalMemoize<T: ?Sized, const IS_FROM_CANONICAL: bool>(PhantomData<T>);
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> Copy
 | 
			
		||||
    for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> Clone
 | 
			
		||||
    for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
 | 
			
		||||
{
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> Eq
 | 
			
		||||
    for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> PartialEq
 | 
			
		||||
    for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
 | 
			
		||||
{
 | 
			
		||||
    fn eq(&self, _other: &Self) -> bool {
 | 
			
		||||
        true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized, const IS_FROM_CANONICAL: bool> Hash
 | 
			
		||||
    for PhantomConstCanonicalMemoize<T, IS_FROM_CANONICAL>
 | 
			
		||||
{
 | 
			
		||||
    fn hash<H: Hasher>(&self, _state: &mut H) {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> Memoize for PhantomConstCanonicalMemoize<T, false> {
 | 
			
		||||
    type Input = Interned<T>;
 | 
			
		||||
    type InputOwned = Interned<T>;
 | 
			
		||||
    type Output = Interned<PhantomConstCanonicalValue>;
 | 
			
		||||
 | 
			
		||||
    fn inner(self, input: &Self::Input) -> Self::Output {
 | 
			
		||||
        Intern::intern_sized(PhantomConstCanonicalValue::from_json_value(
 | 
			
		||||
            serde_json::to_value(input)
 | 
			
		||||
                .expect("serialization failed when constructing a canonical PhantomConst"),
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> Memoize for PhantomConstCanonicalMemoize<T, true> {
 | 
			
		||||
    type Input = Interned<PhantomConstCanonicalValue>;
 | 
			
		||||
    type InputOwned = Interned<PhantomConstCanonicalValue>;
 | 
			
		||||
    type Output = Interned<T>;
 | 
			
		||||
 | 
			
		||||
    fn inner(self, input: &Self::Input) -> Self::Output {
 | 
			
		||||
        PhantomConstValue::deserialize(input.as_json_value()).expect("deserialization failed ")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> PhantomConst<T>
 | 
			
		||||
where
 | 
			
		||||
    Interned<T>: Default,
 | 
			
		||||
{
 | 
			
		||||
    pub const fn default() -> Self {
 | 
			
		||||
        PhantomConst {
 | 
			
		||||
            value: LazyInterned::new_lazy(&Interned::<T>::default),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> PhantomConst<T> {
 | 
			
		||||
    pub fn new(value: Interned<T>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            value: LazyInterned::Interned(value),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get(self) -> Interned<T> {
 | 
			
		||||
        self.value.interned()
 | 
			
		||||
    }
 | 
			
		||||
    pub fn type_properties(self) -> TypeProperties {
 | 
			
		||||
        <()>::TYPE_PROPERTIES
 | 
			
		||||
    }
 | 
			
		||||
    pub fn can_connect(self, other: Self) -> bool {
 | 
			
		||||
        self == other
 | 
			
		||||
    }
 | 
			
		||||
    pub fn canonical_phantom_const(self) -> PhantomConst {
 | 
			
		||||
        if let Some(&retval) = <dyn Any>::downcast_ref::<PhantomConst>(&self) {
 | 
			
		||||
            return retval;
 | 
			
		||||
        }
 | 
			
		||||
        <PhantomConst>::new(
 | 
			
		||||
            PhantomConstCanonicalMemoize::<T, false>(PhantomData).get_owned(self.get()),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    pub fn from_canonical_phantom_const(canonical_type: PhantomConst) -> Self {
 | 
			
		||||
        if let Some(&retval) = <dyn Any>::downcast_ref::<Self>(&canonical_type) {
 | 
			
		||||
            return retval;
 | 
			
		||||
        }
 | 
			
		||||
        Self::new(
 | 
			
		||||
            PhantomConstCanonicalMemoize::<T, true>(PhantomData).get_owned(canonical_type.get()),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> Type for PhantomConst<T> {
 | 
			
		||||
    type BaseType = PhantomConst;
 | 
			
		||||
    type MaskType = ();
 | 
			
		||||
    impl_match_variant_as_self!();
 | 
			
		||||
 | 
			
		||||
    fn mask_type(&self) -> Self::MaskType {
 | 
			
		||||
        ()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn canonical(&self) -> CanonicalType {
 | 
			
		||||
        CanonicalType::PhantomConst(self.canonical_phantom_const())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn from_canonical(canonical_type: CanonicalType) -> Self {
 | 
			
		||||
        let CanonicalType::PhantomConst(phantom_const) = canonical_type else {
 | 
			
		||||
            panic!("expected PhantomConst");
 | 
			
		||||
        };
 | 
			
		||||
        Self::from_canonical_phantom_const(phantom_const)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn source_location() -> SourceLocation {
 | 
			
		||||
        SourceLocation::builtin()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue> StaticType for PhantomConst<T>
 | 
			
		||||
where
 | 
			
		||||
    Interned<T>: Default,
 | 
			
		||||
{
 | 
			
		||||
    const TYPE: Self = Self::default();
 | 
			
		||||
    const MASK_TYPE: Self::MaskType = ();
 | 
			
		||||
    const TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
 | 
			
		||||
    const MASK_TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +26,7 @@ pub use crate::{
 | 
			
		|||
        annotate, connect, connect_any, incomplete_wire, instance, memory, memory_array,
 | 
			
		||||
        memory_with_init, reg_builder, wire, Instance, Module, ModuleBuilder,
 | 
			
		||||
    },
 | 
			
		||||
    phantom_const::PhantomConst,
 | 
			
		||||
    reg::Reg,
 | 
			
		||||
    reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset},
 | 
			
		||||
    source_location::SourceLocation,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -167,6 +167,14 @@ impl<T: Type> CompiledTypeLayout<T> {
 | 
			
		|||
                            body: CompiledTypeLayoutBody::Array { element },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    CanonicalType::PhantomConst(_) => {
 | 
			
		||||
                        let unit_layout = CompiledTypeLayout::get(());
 | 
			
		||||
                        CompiledTypeLayout {
 | 
			
		||||
                            ty: *input,
 | 
			
		||||
                            layout: unit_layout.layout,
 | 
			
		||||
                            body: unit_layout.body,
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    CanonicalType::Bundle(bundle) => {
 | 
			
		||||
                        let mut layout = TypeLayout::empty();
 | 
			
		||||
                        let fields = bundle
 | 
			
		||||
| 
						 | 
				
			
			@ -1792,7 +1800,7 @@ impl Compiler {
 | 
			
		|||
                }
 | 
			
		||||
                .into()
 | 
			
		||||
            }
 | 
			
		||||
            CanonicalType::Bundle(_) => unreachable!(),
 | 
			
		||||
            CanonicalType::Bundle(_) | CanonicalType::PhantomConst(_) => unreachable!(),
 | 
			
		||||
            CanonicalType::AsyncReset(_) => TraceAsyncReset {
 | 
			
		||||
                location: self.make_trace_scalar_helper(
 | 
			
		||||
                    instantiated_module,
 | 
			
		||||
| 
						 | 
				
			
			@ -2009,6 +2017,13 @@ impl Compiler {
 | 
			
		|||
            | CanonicalType::Clock(_) => {
 | 
			
		||||
                self.make_trace_scalar(instantiated_module, target, name, source_location)
 | 
			
		||||
            }
 | 
			
		||||
            CanonicalType::PhantomConst(_) => TraceBundle {
 | 
			
		||||
                name,
 | 
			
		||||
                fields: Interned::default(),
 | 
			
		||||
                ty: Bundle::new(Interned::default()),
 | 
			
		||||
                flow: target.flow(),
 | 
			
		||||
            }
 | 
			
		||||
            .into(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn make_trace_decl(
 | 
			
		||||
| 
						 | 
				
			
			@ -2469,6 +2484,9 @@ impl Compiler {
 | 
			
		|||
                    Expr::field(Expr::<Bundle>::from_canonical(expr.arg()), &field.name)
 | 
			
		||||
                }),
 | 
			
		||||
            ),
 | 
			
		||||
            CanonicalType::PhantomConst(_) => {
 | 
			
		||||
                self.compile_cast_aggregate_to_bits(instantiated_module, [])
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn compile_cast_bits_to(
 | 
			
		||||
| 
						 | 
				
			
			@ -2518,6 +2536,10 @@ impl Compiler {
 | 
			
		|||
            CanonicalType::SyncReset(ty) => Expr::canonical(expr.arg().cast_to(ty)),
 | 
			
		||||
            CanonicalType::Reset(_) => unreachable!(),
 | 
			
		||||
            CanonicalType::Clock(ty) => Expr::canonical(expr.arg().cast_to(ty)),
 | 
			
		||||
            CanonicalType::PhantomConst(ty) => {
 | 
			
		||||
                let _ = self.compile_expr(instantiated_module, Expr::canonical(expr.arg()));
 | 
			
		||||
                Expr::canonical(ty.to_expr())
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        let retval = self.compile_expr(instantiated_module, Expr::canonical(retval));
 | 
			
		||||
        self.compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location())
 | 
			
		||||
| 
						 | 
				
			
			@ -2567,6 +2589,7 @@ impl Compiler {
 | 
			
		|||
                CanonicalType::SyncReset(_) => false,
 | 
			
		||||
                CanonicalType::Reset(_) => false,
 | 
			
		||||
                CanonicalType::Clock(_) => false,
 | 
			
		||||
                CanonicalType::PhantomConst(_) => unreachable!(),
 | 
			
		||||
            };
 | 
			
		||||
            let dest_signed = match Expr::ty(expr) {
 | 
			
		||||
                CanonicalType::UInt(_) => false,
 | 
			
		||||
| 
						 | 
				
			
			@ -2579,6 +2602,7 @@ impl Compiler {
 | 
			
		|||
                CanonicalType::SyncReset(_) => false,
 | 
			
		||||
                CanonicalType::Reset(_) => false,
 | 
			
		||||
                CanonicalType::Clock(_) => false,
 | 
			
		||||
                CanonicalType::PhantomConst(_) => unreachable!(),
 | 
			
		||||
            };
 | 
			
		||||
            self.simple_nary_big_expr(instantiated_module, Expr::ty(expr), [arg], |dest, [src]| {
 | 
			
		||||
                match (src_signed, dest_signed) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2634,6 +2658,9 @@ impl Compiler {
 | 
			
		|||
                    }]
 | 
			
		||||
                })
 | 
			
		||||
                .into(),
 | 
			
		||||
            ExprEnum::PhantomConst(_) => self
 | 
			
		||||
                .compile_aggregate_literal(instantiated_module, Expr::ty(expr), Interned::default())
 | 
			
		||||
                .into(),
 | 
			
		||||
            ExprEnum::BundleLiteral(literal) => self
 | 
			
		||||
                .compile_aggregate_literal(
 | 
			
		||||
                    instantiated_module,
 | 
			
		||||
| 
						 | 
				
			
			@ -3537,6 +3564,7 @@ impl Compiler {
 | 
			
		|||
                CanonicalType::SyncReset(_) => unreachable!(),
 | 
			
		||||
                CanonicalType::Reset(_) => unreachable!(),
 | 
			
		||||
                CanonicalType::Clock(_) => unreachable!(),
 | 
			
		||||
                CanonicalType::PhantomConst(_) => unreachable!("PhantomConst mismatch"),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        let Some(target) = lhs.target() else {
 | 
			
		||||
| 
						 | 
				
			
			@ -3901,6 +3929,7 @@ impl Compiler {
 | 
			
		|||
                    CanonicalType::SyncReset(_) => false,
 | 
			
		||||
                    CanonicalType::Reset(_) => false,
 | 
			
		||||
                    CanonicalType::Clock(_) => false,
 | 
			
		||||
                    CanonicalType::PhantomConst(_) => unreachable!(),
 | 
			
		||||
                };
 | 
			
		||||
                let width = data_layout.ty.bit_width();
 | 
			
		||||
                if let Some(MemoryPortReadInsns {
 | 
			
		||||
| 
						 | 
				
			
			@ -5909,6 +5938,7 @@ impl SimValue<CanonicalType> {
 | 
			
		|||
            CanonicalType::Clock(ty) => {
 | 
			
		||||
                Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits)).cast_to(ty))
 | 
			
		||||
            }
 | 
			
		||||
            CanonicalType::PhantomConst(ty) => Expr::canonical(ty.to_expr()),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -6312,7 +6342,8 @@ impl ToSimValue<CanonicalType> for bool {
 | 
			
		|||
            | CanonicalType::SInt(_)
 | 
			
		||||
            | CanonicalType::Array(_)
 | 
			
		||||
            | CanonicalType::Enum(_)
 | 
			
		||||
            | CanonicalType::Bundle(_) => {
 | 
			
		||||
            | CanonicalType::Bundle(_)
 | 
			
		||||
            | CanonicalType::PhantomConst(_) => {
 | 
			
		||||
                panic!("can't create SimValue from bool: expected value of type: {ty:?}");
 | 
			
		||||
            }
 | 
			
		||||
            CanonicalType::Bool(_)
 | 
			
		||||
| 
						 | 
				
			
			@ -6977,6 +7008,7 @@ impl SimulationImpl {
 | 
			
		|||
                    CanonicalType::SyncReset(_) => false,
 | 
			
		||||
                    CanonicalType::Reset(_) => false,
 | 
			
		||||
                    CanonicalType::Clock(_) => false,
 | 
			
		||||
                    CanonicalType::PhantomConst(_) => unreachable!(),
 | 
			
		||||
                };
 | 
			
		||||
                match compiled_value.range.len() {
 | 
			
		||||
                    TypeLen::A_SMALL_SLOT => read_write_small_scalar(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,8 +9,10 @@ use crate::{
 | 
			
		|||
    expr::Expr,
 | 
			
		||||
    int::{Bool, SInt, UInt},
 | 
			
		||||
    intern::{Intern, Interned},
 | 
			
		||||
    phantom_const::PhantomConst,
 | 
			
		||||
    reset::{AsyncReset, Reset, SyncReset},
 | 
			
		||||
    source_location::SourceLocation,
 | 
			
		||||
    util::ConstUsize,
 | 
			
		||||
};
 | 
			
		||||
use std::{fmt, hash::Hash, iter::FusedIterator, ops::Index};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -35,6 +37,7 @@ pub enum CanonicalType {
 | 
			
		|||
    SyncReset(SyncReset),
 | 
			
		||||
    Reset(Reset),
 | 
			
		||||
    Clock(Clock),
 | 
			
		||||
    PhantomConst(PhantomConst),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Debug for CanonicalType {
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +53,7 @@ impl fmt::Debug for CanonicalType {
 | 
			
		|||
            Self::SyncReset(v) => v.fmt(f),
 | 
			
		||||
            Self::Reset(v) => v.fmt(f),
 | 
			
		||||
            Self::Clock(v) => v.fmt(f),
 | 
			
		||||
            Self::PhantomConst(v) => v.fmt(f),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +71,7 @@ impl CanonicalType {
 | 
			
		|||
            CanonicalType::SyncReset(v) => v.type_properties(),
 | 
			
		||||
            CanonicalType::Reset(v) => v.type_properties(),
 | 
			
		||||
            CanonicalType::Clock(v) => v.type_properties(),
 | 
			
		||||
            CanonicalType::PhantomConst(v) => v.type_properties(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn is_passive(self) -> bool {
 | 
			
		||||
| 
						 | 
				
			
			@ -143,6 +148,12 @@ impl CanonicalType {
 | 
			
		|||
                };
 | 
			
		||||
                lhs.can_connect(rhs)
 | 
			
		||||
            }
 | 
			
		||||
            CanonicalType::PhantomConst(lhs) => {
 | 
			
		||||
                let CanonicalType::PhantomConst(rhs) = rhs else {
 | 
			
		||||
                    return false;
 | 
			
		||||
                };
 | 
			
		||||
                lhs.can_connect(rhs)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +177,7 @@ impl<T: 'static + Send + Sync> MatchVariantAndInactiveScope for MatchVariantWith
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
pub trait FillInDefaultedGenerics {
 | 
			
		||||
    type Type: Type;
 | 
			
		||||
    type Type;
 | 
			
		||||
    fn fill_in_defaulted_generics(self) -> Self::Type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -178,6 +189,22 @@ impl<T: Type> FillInDefaultedGenerics for T {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl FillInDefaultedGenerics for usize {
 | 
			
		||||
    type Type = usize;
 | 
			
		||||
 | 
			
		||||
    fn fill_in_defaulted_generics(self) -> Self::Type {
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<const V: usize> FillInDefaultedGenerics for ConstUsize<V> {
 | 
			
		||||
    type Type = ConstUsize<V>;
 | 
			
		||||
 | 
			
		||||
    fn fill_in_defaulted_generics(self) -> Self::Type {
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod sealed {
 | 
			
		||||
    pub trait TypeOrDefaultSealed {}
 | 
			
		||||
    pub trait BaseTypeSealed {}
 | 
			
		||||
| 
						 | 
				
			
			@ -205,6 +232,7 @@ impl_base_type!(AsyncReset);
 | 
			
		|||
impl_base_type!(SyncReset);
 | 
			
		||||
impl_base_type!(Reset);
 | 
			
		||||
impl_base_type!(Clock);
 | 
			
		||||
impl_base_type!(PhantomConst);
 | 
			
		||||
 | 
			
		||||
impl sealed::BaseTypeSealed for CanonicalType {}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -299,6 +327,7 @@ impl Type for CanonicalType {
 | 
			
		|||
            CanonicalType::SyncReset(v) => v.mask_type().canonical(),
 | 
			
		||||
            CanonicalType::Reset(v) => v.mask_type().canonical(),
 | 
			
		||||
            CanonicalType::Clock(v) => v.mask_type().canonical(),
 | 
			
		||||
            CanonicalType::PhantomConst(v) => v.mask_type().canonical(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn canonical(&self) -> CanonicalType {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,8 @@
 | 
			
		|||
                "AsyncReset": "Visible",
 | 
			
		||||
                "SyncReset": "Visible",
 | 
			
		||||
                "Reset": "Visible",
 | 
			
		||||
                "Clock": "Visible"
 | 
			
		||||
                "Clock": "Visible",
 | 
			
		||||
                "PhantomConst": "Visible"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "Bundle": {
 | 
			
		||||
| 
						 | 
				
			
			@ -1262,6 +1263,12 @@
 | 
			
		|||
                "ArrayElement": "Visible",
 | 
			
		||||
                "DynArrayElement": "Visible"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "PhantomConst": {
 | 
			
		||||
            "data": {
 | 
			
		||||
                "$kind": "Opaque"
 | 
			
		||||
            },
 | 
			
		||||
            "generics": "<T: ?Sized + crate::phantom_const::PhantomConstValue>"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue