fayalite/crates/fayalite/src/expr.rs

795 lines
22 KiB
Rust

// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
array::{Array, ArrayType},
bundle::{Bundle, BundleType},
enum_::{Enum, EnumType},
expr::{
ops::ExprCastTo,
target::{GetTarget, Target},
},
int::{Bool, DynSize, IntType, SIntType, SIntValue, Size, SizeType, UInt, UIntType, UIntValue},
intern::{Intern, Interned},
memory::{DynPortType, MemPort, PortType},
module::{
transform::visit::{Fold, Folder, Visit, Visitor},
Instance, ModuleIO,
},
phantom_const::PhantomConst,
reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
ty::{CanonicalType, StaticType, Type, TypeWithDeref},
wire::Wire,
};
use bitvec::slice::BitSlice;
use std::{convert::Infallible, fmt, ops::Deref};
pub mod ops;
pub mod target;
macro_rules! expr_enum {
(
pub enum $ExprEnum:ident {
$($Variant:ident($VariantTy:ty),)*
}
) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum $ExprEnum {
$($Variant($VariantTy),)*
}
impl fmt::Debug for $ExprEnum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
$(Self::$Variant(v) => v.fmt(f),)*
}
}
}
$(impl From<$VariantTy> for $ExprEnum {
fn from(v: $VariantTy) -> Self {
Self::$Variant(v)
}
})*
impl<State: Folder + ?Sized> Fold<State> for $ExprEnum {
fn fold(self, state: &mut State) -> Result<Self, State::Error> {
state.fold_expr_enum(self)
}
fn default_fold(self, state: &mut State) -> Result<Self, State::Error> {
match self {
$(Self::$Variant(v) => Fold::fold(v, state).map(Self::$Variant),)*
}
}
}
impl<State: Visitor + ?Sized> Visit<State> for $ExprEnum {
fn visit(&self, state: &mut State) -> Result<(), State::Error> {
state.visit_expr_enum(self)
}
fn default_visit(&self, state: &mut State) -> Result<(), State::Error> {
match self {
$(Self::$Variant(v) => Visit::visit(v, state),)*
}
}
}
impl ToExpr for $ExprEnum {
type Type = CanonicalType;
fn to_expr(&self) -> Expr<Self::Type> {
match self {
$(Self::$Variant(v) => Expr::canonical(v.to_expr()),)*
}
}
}
impl GetTarget for $ExprEnum {
fn target(&self) -> Option<Interned<Target>> {
match self {
$(Self::$Variant(v) => v.target(),)*
}
}
}
impl ToLiteralBits for $ExprEnum {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
match self {
$(Self::$Variant(v) => v.to_literal_bits(),)*
}
}
}
};
}
expr_enum! {
pub enum ExprEnum {
UIntLiteral(Interned<UIntValue>),
SIntLiteral(Interned<SIntValue>),
BoolLiteral(bool),
PhantomConst(PhantomConst),
BundleLiteral(ops::BundleLiteral),
ArrayLiteral(ops::ArrayLiteral<CanonicalType, DynSize>),
EnumLiteral(ops::EnumLiteral),
Uninit(ops::Uninit),
NotU(ops::NotU),
NotS(ops::NotS),
NotB(ops::NotB),
Neg(ops::Neg),
BitAndU(ops::BitAndU),
BitAndS(ops::BitAndS),
BitAndB(ops::BitAndB),
BitOrU(ops::BitOrU),
BitOrS(ops::BitOrS),
BitOrB(ops::BitOrB),
BitXorU(ops::BitXorU),
BitXorS(ops::BitXorS),
BitXorB(ops::BitXorB),
AddU(ops::AddU),
AddS(ops::AddS),
SubU(ops::SubU),
SubS(ops::SubS),
MulU(ops::MulU),
MulS(ops::MulS),
DivU(ops::DivU),
DivS(ops::DivS),
RemU(ops::RemU),
RemS(ops::RemS),
DynShlU(ops::DynShlU),
DynShlS(ops::DynShlS),
DynShrU(ops::DynShrU),
DynShrS(ops::DynShrS),
FixedShlU(ops::FixedShlU),
FixedShlS(ops::FixedShlS),
FixedShrU(ops::FixedShrU),
FixedShrS(ops::FixedShrS),
CmpLtB(ops::CmpLtB),
CmpLeB(ops::CmpLeB),
CmpGtB(ops::CmpGtB),
CmpGeB(ops::CmpGeB),
CmpEqB(ops::CmpEqB),
CmpNeB(ops::CmpNeB),
CmpLtU(ops::CmpLtU),
CmpLeU(ops::CmpLeU),
CmpGtU(ops::CmpGtU),
CmpGeU(ops::CmpGeU),
CmpEqU(ops::CmpEqU),
CmpNeU(ops::CmpNeU),
CmpLtS(ops::CmpLtS),
CmpLeS(ops::CmpLeS),
CmpGtS(ops::CmpGtS),
CmpGeS(ops::CmpGeS),
CmpEqS(ops::CmpEqS),
CmpNeS(ops::CmpNeS),
CastUIntToUInt(ops::CastUIntToUInt),
CastUIntToSInt(ops::CastUIntToSInt),
CastSIntToUInt(ops::CastSIntToUInt),
CastSIntToSInt(ops::CastSIntToSInt),
CastBoolToUInt(ops::CastBoolToUInt),
CastBoolToSInt(ops::CastBoolToSInt),
CastUIntToBool(ops::CastUIntToBool),
CastSIntToBool(ops::CastSIntToBool),
CastBoolToSyncReset(ops::CastBoolToSyncReset),
CastUIntToSyncReset(ops::CastUIntToSyncReset),
CastSIntToSyncReset(ops::CastSIntToSyncReset),
CastBoolToAsyncReset(ops::CastBoolToAsyncReset),
CastUIntToAsyncReset(ops::CastUIntToAsyncReset),
CastSIntToAsyncReset(ops::CastSIntToAsyncReset),
CastSyncResetToBool(ops::CastSyncResetToBool),
CastSyncResetToUInt(ops::CastSyncResetToUInt),
CastSyncResetToSInt(ops::CastSyncResetToSInt),
CastSyncResetToReset(ops::CastSyncResetToReset),
CastAsyncResetToBool(ops::CastAsyncResetToBool),
CastAsyncResetToUInt(ops::CastAsyncResetToUInt),
CastAsyncResetToSInt(ops::CastAsyncResetToSInt),
CastAsyncResetToReset(ops::CastAsyncResetToReset),
CastResetToBool(ops::CastResetToBool),
CastResetToUInt(ops::CastResetToUInt),
CastResetToSInt(ops::CastResetToSInt),
CastBoolToClock(ops::CastBoolToClock),
CastUIntToClock(ops::CastUIntToClock),
CastSIntToClock(ops::CastSIntToClock),
CastClockToBool(ops::CastClockToBool),
CastClockToUInt(ops::CastClockToUInt),
CastClockToSInt(ops::CastClockToSInt),
FieldAccess(ops::FieldAccess),
VariantAccess(ops::VariantAccess),
ArrayIndex(ops::ArrayIndex),
DynArrayIndex(ops::DynArrayIndex),
ReduceBitAndU(ops::ReduceBitAndU),
ReduceBitAndS(ops::ReduceBitAndS),
ReduceBitOrU(ops::ReduceBitOrU),
ReduceBitOrS(ops::ReduceBitOrS),
ReduceBitXorU(ops::ReduceBitXorU),
ReduceBitXorS(ops::ReduceBitXorS),
SliceUInt(ops::SliceUInt),
SliceSInt(ops::SliceSInt),
CastToBits(ops::CastToBits),
CastBitsTo(ops::CastBitsTo),
ModuleIO(ModuleIO<CanonicalType>),
Instance(Instance<Bundle>),
Wire(Wire<CanonicalType>),
Reg(Reg<CanonicalType, Reset>),
RegSync(Reg<CanonicalType, SyncReset>),
RegAsync(Reg<CanonicalType, AsyncReset>),
MemPort(MemPort<DynPortType>),
}
}
impl From<UIntValue> for ExprEnum {
fn from(value: UIntValue) -> Self {
ExprEnum::UIntLiteral(Intern::intern_sized(value))
}
}
impl From<SIntValue> for ExprEnum {
fn from(value: SIntValue) -> Self {
ExprEnum::SIntLiteral(Intern::intern_sized(value))
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[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 {}
pub trait ToLiteralBits {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr>;
}
impl ToLiteralBits for Result<Interned<BitSlice>, NotALiteralExpr> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
*self
}
}
impl ToLiteralBits for Interned<BitSlice> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Ok(*self)
}
}
impl ToLiteralBits for NotALiteralExpr {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(*self)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Expr<T: Type> {
__enum: Interned<ExprEnum>,
__ty: T,
__flow: Flow,
}
impl<T: Type + fmt::Debug> fmt::Debug for Expr<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(debug_assertions)]
{
let Self {
__enum,
__ty,
__flow,
} = self;
let expr_ty = __ty.canonical();
let enum_ty = __enum.to_expr().__ty;
assert_eq!(expr_ty, enum_ty, "expr ty mismatch:\nExpr {{\n__enum: {__enum:?},\n__ty: {__ty:?},\n__flow: {__flow:?}\n}}");
}
self.__enum.fmt(f)
}
}
impl<T: Type> Expr<T> {
pub fn expr_enum(this: Self) -> Interned<ExprEnum> {
this.__enum
}
pub fn ty(this: Self) -> T {
this.__ty
}
pub fn flow(this: Self) -> Flow {
this.__flow
}
pub fn canonical(this: Self) -> Expr<CanonicalType> {
Expr {
__enum: this.__enum,
__ty: this.__ty.canonical(),
__flow: this.__flow,
}
}
pub fn from_canonical(this: Expr<CanonicalType>) -> Self {
Expr {
__enum: this.__enum,
__ty: T::from_canonical(this.__ty),
__flow: this.__flow,
}
}
pub fn from_dyn_int(this: Expr<T::Dyn>) -> Self
where
T: IntType,
{
Expr {
__enum: this.__enum,
__ty: T::from_dyn_int(this.__ty),
__flow: this.__flow,
}
}
pub fn as_dyn_int(this: Self) -> Expr<T::Dyn>
where
T: IntType,
{
Expr {
__enum: this.__enum,
__ty: this.__ty.as_dyn_int(),
__flow: this.__flow,
}
}
pub fn as_bundle(this: Self) -> Expr<Bundle>
where
T: BundleType,
{
Expr {
__enum: this.__enum,
__ty: Bundle::new(this.__ty.fields()),
__flow: this.__flow,
}
}
pub fn from_bundle(this: Expr<Bundle>) -> Self
where
T: BundleType,
{
Expr {
__enum: this.__enum,
__ty: T::from_canonical(CanonicalType::Bundle(this.__ty)),
__flow: this.__flow,
}
}
#[track_caller]
pub fn field<FieldType: Type>(this: Self, name: &str) -> Expr<FieldType>
where
T: BundleType,
{
ops::FieldAccess::new_by_name(Self::as_bundle(this), name.intern()).to_expr()
}
pub fn as_enum(this: Self) -> Expr<Enum>
where
T: EnumType,
{
Expr {
__enum: this.__enum,
__ty: Enum::new(this.__ty.variants()),
__flow: this.__flow,
}
}
pub fn from_enum(this: Expr<Enum>) -> Self
where
T: EnumType,
{
Expr {
__enum: this.__enum,
__ty: T::from_canonical(CanonicalType::Enum(this.__ty)),
__flow: this.__flow,
}
}
}
impl<T: Type> ToLiteralBits for Expr<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.__enum.to_literal_bits()
}
}
impl<T: Type> GetTarget for Expr<T> {
fn target(&self) -> Option<Interned<Target>> {
self.__enum.target()
}
}
impl<T: TypeWithDeref> Deref for Expr<T> {
type Target = T::MatchVariant;
fn deref(&self) -> &Self::Target {
T::expr_deref(self)
}
}
impl<T: Type, Len: Size> Expr<ArrayType<T, Len>> {
pub fn as_dyn_array(this: Self) -> Expr<Array> {
Expr {
__enum: this.__enum,
__ty: this.__ty.as_dyn_array(),
__flow: this.__flow,
}
}
}
impl<T: Type, State: Folder + ?Sized> Fold<State> for Expr<T> {
fn fold(self, state: &mut State) -> Result<Self, State::Error> {
state.fold_expr(self)
}
fn default_fold(self, state: &mut State) -> Result<Self, State::Error> {
Ok(Expr::from_canonical(self.__enum.fold(state)?.to_expr()))
}
}
impl<T: Type, State: Visitor + ?Sized> Visit<State> for Expr<T> {
fn visit(&self, state: &mut State) -> Result<(), State::Error> {
state.visit_expr(self)
}
fn default_visit(&self, state: &mut State) -> Result<(), State::Error> {
self.__enum.visit(state)
}
}
pub trait ToExpr {
type Type: Type;
fn to_expr(&self) -> Expr<Self::Type>;
}
impl<T: Type> ToExpr for Expr<T> {
type Type = T;
fn to_expr(&self) -> Expr<Self::Type> {
*self
}
}
impl<T: ?Sized + ToExpr> ToExpr for &'_ T {
type Type = T::Type;
fn to_expr(&self) -> Expr<Self::Type> {
T::to_expr(self)
}
}
impl<T: ?Sized + ToExpr> ToExpr for &'_ mut T {
type Type = T::Type;
fn to_expr(&self) -> Expr<Self::Type> {
T::to_expr(self)
}
}
impl<T: ?Sized + ToExpr> ToExpr for Box<T> {
type Type = T::Type;
fn to_expr(&self) -> Expr<Self::Type> {
T::to_expr(self)
}
}
impl<T: ?Sized + ToExpr + Send + Sync + 'static> ToExpr for Interned<T> {
type Type = T::Type;
fn to_expr(&self) -> Expr<Self::Type> {
T::to_expr(self)
}
}
impl<Width: Size> ToExpr for UIntValue<Width> {
type Type = UIntType<Width>;
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::UIntLiteral(self.clone().as_dyn_int().intern()).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
impl<Width: Size> ToExpr for SIntValue<Width> {
type Type = SIntType<Width>;
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::SIntLiteral(self.clone().as_dyn_int().intern()).intern(),
__ty: self.ty(),
__flow: Flow::Source,
}
}
}
impl ToExpr for bool {
type Type = Bool;
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::BoolLiteral(*self).intern(),
__ty: Bool,
__flow: Flow::Source,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Flow {
Source,
Sink,
Duplex,
}
impl Flow {
pub const fn flip(self) -> Flow {
match self {
Flow::Source => Flow::Sink,
Flow::Sink => Flow::Source,
Flow::Duplex => Flow::Duplex,
}
}
pub const fn flip_if(self, flipped: bool) -> Flow {
if flipped {
self.flip()
} else {
self
}
}
}
impl<T: Type> ToExpr for ModuleIO<T> {
type Type = T;
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::ModuleIO(self.canonical()).intern_sized(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}
impl<T: Type> ToLiteralBits for ModuleIO<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl<T: Type> GetTarget for ModuleIO<T> {
fn target(&self) -> Option<Interned<Target>> {
Some(Intern::intern_sized(self.canonical().into()))
}
}
impl<T: BundleType> ToExpr for Instance<T> {
type Type = T;
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::Instance(self.canonical()).intern_sized(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}
impl<T: BundleType> ToLiteralBits for Instance<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl<T: BundleType> GetTarget for Instance<T> {
fn target(&self) -> Option<Interned<Target>> {
Some(Intern::intern_sized(self.canonical().into()))
}
}
impl<T: Type> ToExpr for Wire<T> {
type Type = T;
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::Wire(self.canonical()).intern_sized(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}
impl<T: Type> ToLiteralBits for Wire<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl<T: Type> GetTarget for Wire<T> {
fn target(&self) -> Option<Interned<Target>> {
Some(Intern::intern_sized(self.canonical().into()))
}
}
impl<T: Type, R: ResetType> ToExpr for Reg<T, R> {
type Type = T;
fn to_expr(&self) -> Expr<Self::Type> {
struct Dispatch;
impl ResetTypeDispatch for Dispatch {
type Input<T: ResetType> = Reg<CanonicalType, T>;
type Output<T: ResetType> = ExprEnum;
fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset> {
ExprEnum::Reg(input)
}
fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset> {
ExprEnum::RegSync(input)
}
fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset> {
ExprEnum::RegAsync(input)
}
}
Expr {
__enum: R::dispatch(self.canonical(), Dispatch).intern_sized(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}
impl<T: Type, R: ResetType> ToLiteralBits for Reg<T, R> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl<T: Type, R: ResetType> GetTarget for Reg<T, R> {
fn target(&self) -> Option<Interned<Target>> {
Some(Intern::intern_sized(self.canonical().into()))
}
}
impl<T: PortType> ToExpr for MemPort<T> {
type Type = T::Port;
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::MemPort(self.canonical()).intern_sized(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}
impl<T: PortType> ToLiteralBits for MemPort<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl<T: PortType> GetTarget for MemPort<T> {
fn target(&self) -> Option<Interned<Target>> {
Some(Intern::intern_sized(self.canonical().into()))
}
}
pub trait HdlPartialEq<Rhs> {
fn cmp_eq(self, rhs: Rhs) -> Expr<Bool>;
fn cmp_ne(self, rhs: Rhs) -> Expr<Bool>;
}
pub trait HdlPartialOrd<Rhs>: HdlPartialEq<Rhs> {
fn cmp_lt(self, rhs: Rhs) -> Expr<Bool>;
fn cmp_le(self, rhs: Rhs) -> Expr<Bool>;
fn cmp_gt(self, rhs: Rhs) -> Expr<Bool>;
fn cmp_ge(self, rhs: Rhs) -> Expr<Bool>;
}
pub trait ReduceBits {
type UIntOutput;
type BoolOutput;
fn reduce_bitand(self) -> Self::UIntOutput;
fn reduce_bitor(self) -> Self::UIntOutput;
fn reduce_bitxor(self) -> Self::UIntOutput;
fn any_one_bits(self) -> Self::BoolOutput;
fn any_zero_bits(self) -> Self::BoolOutput;
fn all_one_bits(self) -> Self::BoolOutput;
fn all_zero_bits(self) -> Self::BoolOutput;
fn parity_odd(self) -> Self::BoolOutput;
fn parity_even(self) -> Self::BoolOutput;
}
pub trait CastToBits {
fn cast_to_bits(&self) -> Expr<UInt>;
}
impl<T: ToExpr + ?Sized> CastToBits for T {
fn cast_to_bits(&self) -> Expr<UInt> {
ops::CastToBits::new(Expr::canonical(self.to_expr())).to_expr()
}
}
pub trait CastBitsTo {
#[track_caller]
fn cast_bits_to<T: Type>(&self, ty: T) -> Expr<T>;
}
impl<T: ToExpr<Type = UIntType<Width>> + ?Sized, Width: Size> CastBitsTo for T {
fn cast_bits_to<ToType: Type>(&self, ty: ToType) -> Expr<ToType> {
ops::CastBitsTo::new(Expr::as_dyn_int(self.to_expr()), ty).to_expr()
}
}
pub trait CastTo: ToExpr {
fn cast_to<ToType: Type>(&self, to_type: ToType) -> Expr<ToType>
where
Self::Type: ExprCastTo<ToType>,
{
ExprCastTo::cast_to(self.to_expr(), to_type)
}
fn cast_to_static<ToType: StaticType>(&self) -> Expr<ToType>
where
Self::Type: ExprCastTo<ToType>,
{
ExprCastTo::cast_to(self.to_expr(), ToType::TYPE)
}
}
impl<T: ToExpr + ?Sized> CastTo for T {}
#[doc(hidden)]
pub fn check_match_expr<T: Type>(
_expr: Expr<T>,
_check_fn: impl FnOnce(T::MatchVariant, Infallible),
) {
}
pub trait MakeUninitExpr: Type {
fn uninit(self) -> Expr<Self>;
}
impl<T: Type> MakeUninitExpr for T {
fn uninit(self) -> Expr<Self> {
ops::Uninit::new(self).to_expr()
}
}
pub fn repeat<T: Type, L: SizeType>(
element: impl ToExpr<Type = T>,
len: L,
) -> Expr<ArrayType<T, L::Size>> {
let element = element.to_expr();
let canonical_element = Expr::canonical(element);
ops::ArrayLiteral::new(
Expr::ty(element),
std::iter::repeat(canonical_element)
.take(L::Size::as_usize(len))
.collect(),
)
.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())
}
}