use super::{Interner, Ty, TyFlags, TyKind};
use solar_ast::{DataLocation, ElementaryType, TypeSize};
pub struct CommonTypes<'gcx> {
pub unit: Ty<'gcx>,
pub bool: Ty<'gcx>,
pub address: Ty<'gcx>,
pub address_payable: Ty<'gcx>,
pub string: Ty<'gcx>,
pub string_ref: EachDataLoc<Ty<'gcx>>,
pub bytes: Ty<'gcx>,
pub bytes_ref: EachDataLoc<Ty<'gcx>>,
ints: [Ty<'gcx>; 32],
uints: [Ty<'gcx>; 32],
fbs: [Ty<'gcx>; 32],
}
impl<'gcx> CommonTypes<'gcx> {
#[instrument(name = "new_common_types", level = "debug", skip_all)]
#[inline]
pub(super) fn new(interner: &Interner<'gcx>, bump: &'gcx bumpalo::Bump) -> Self {
use ElementaryType::*;
use TyKind::*;
use std::array::from_fn;
let mk = |kind| interner.intern_ty_with_flags(bump, kind, |_| TyFlags::empty());
let mk_refs = |ty| EachDataLoc {
storage: mk(Ref(ty, DataLocation::Storage)),
transient: mk(Ref(ty, DataLocation::Transient)),
memory: mk(Ref(ty, DataLocation::Memory)),
calldata: mk(Ref(ty, DataLocation::Calldata)),
};
let string = mk(Elementary(String));
let bytes = mk(Elementary(Bytes));
Self {
unit: mk(Tuple(&[])),
bool: mk(Elementary(Bool)),
address: mk(Elementary(Address(false))),
address_payable: mk(Elementary(Address(true))),
string,
string_ref: mk_refs(string),
bytes,
bytes_ref: mk_refs(bytes),
ints: from_fn(|i| mk(Elementary(Int(TypeSize::new(i as u8 + 1).unwrap())))),
uints: from_fn(|i| mk(Elementary(UInt(TypeSize::new(i as u8 + 1).unwrap())))),
fbs: from_fn(|i| mk(Elementary(FixedBytes(TypeSize::new(i as u8 + 1).unwrap())))),
}
}
#[inline]
#[track_caller]
pub fn int(&self, bits: u16) -> Ty<'gcx> {
self.int_(TypeSize::new_int_bits(bits))
}
pub fn int_(&self, size: TypeSize) -> Ty<'gcx> {
self.ints[size.bytes() as usize - 1]
}
#[inline]
#[track_caller]
pub fn uint(&self, bits: u16) -> Ty<'gcx> {
self.uint_(TypeSize::new_int_bits(bits))
}
pub fn uint_(&self, size: TypeSize) -> Ty<'gcx> {
self.uints[size.bytes() as usize - 1]
}
#[inline]
#[track_caller]
pub fn fixed_bytes(&self, bytes: u8) -> Ty<'gcx> {
self.fixed_bytes_(TypeSize::new_fb_bytes(bytes))
}
pub fn fixed_bytes_(&self, size: TypeSize) -> Ty<'gcx> {
self.fbs[size.bytes() as usize - 1]
}
}
pub struct EachDataLoc<T> {
pub storage: T,
pub transient: T,
pub memory: T,
pub calldata: T,
}
impl<T> EachDataLoc<T> {
#[inline]
pub fn get(&self, loc: DataLocation) -> T
where
T: Copy,
{
match loc {
DataLocation::Storage => self.storage,
DataLocation::Transient => self.transient,
DataLocation::Memory => self.memory,
DataLocation::Calldata => self.calldata,
}
}
#[inline]
pub fn get_ref(&self, loc: DataLocation) -> &T {
match loc {
DataLocation::Storage => &self.storage,
DataLocation::Transient => &self.transient,
DataLocation::Memory => &self.memory,
DataLocation::Calldata => &self.calldata,
}
}
#[inline]
pub fn get_mut(&mut self, loc: DataLocation) -> &mut T {
match loc {
DataLocation::Storage => &mut self.storage,
DataLocation::Transient => &mut self.transient,
DataLocation::Memory => &mut self.memory,
DataLocation::Calldata => &mut self.calldata,
}
}
}
impl<T> std::ops::Index<DataLocation> for EachDataLoc<T> {
type Output = T;
#[inline]
fn index(&self, loc: DataLocation) -> &Self::Output {
self.get_ref(loc)
}
}
impl<T> std::ops::IndexMut<DataLocation> for EachDataLoc<T> {
#[inline]
fn index_mut(&mut self, loc: DataLocation) -> &mut Self::Output {
self.get_mut(loc)
}
}