Skip to main content

solar_sema/ty/
common.rs

1use super::{Interner, Ty, TyKind};
2use solar_ast::{DataLocation, ElementaryType, TypeSize};
3use solar_interface::diagnostics::ErrorGuaranteed;
4
5/// Pre-interned types.
6pub struct CommonTypes<'gcx> {
7    /// The unit type `()`, AKA empty tuple, void.
8    #[doc(alias = "empty_tuple", alias = "void")]
9    pub unit: Ty<'gcx>,
10    /// `bool`.
11    pub bool: Ty<'gcx>,
12
13    /// `address`.
14    pub address: Ty<'gcx>,
15    /// `address payable`.
16    pub address_payable: Ty<'gcx>,
17
18    /// `string`.
19    pub string: Ty<'gcx>,
20    /// `string` references.
21    pub string_ref: EachDataLoc<Ty<'gcx>>,
22
23    /// `bytes`.
24    pub bytes: Ty<'gcx>,
25    /// `bytes` references.
26    pub bytes_ref: EachDataLoc<Ty<'gcx>>,
27
28    ints: [Ty<'gcx>; 32],
29    uints: [Ty<'gcx>; 32],
30    fbs: [Ty<'gcx>; 32],
31
32    pub(super) __err_do_not_use: Ty<'gcx>,
33}
34
35impl<'gcx> CommonTypes<'gcx> {
36    #[instrument(name = "new_common_types", level = "debug", skip_all)]
37    #[inline]
38    pub(super) fn new(interner: &Interner<'gcx>, bump: &'gcx bumpalo::Bump) -> Self {
39        use ElementaryType::*;
40        use TyKind::*;
41        use std::array::from_fn;
42
43        let mk = |kind| interner.intern_ty(bump, kind);
44        let mk_refs = |ty| EachDataLoc {
45            storage: mk(Ref(ty, DataLocation::Storage)),
46            transient: mk(Ref(ty, DataLocation::Transient)),
47            memory: mk(Ref(ty, DataLocation::Memory)),
48            calldata: mk(Ref(ty, DataLocation::Calldata)),
49        };
50
51        let string = mk(Elementary(String));
52        let bytes = mk(Elementary(Bytes));
53
54        Self {
55            unit: mk(Tuple(&[])),
56            // never: mk(Elementary(Never)),
57            bool: mk(Elementary(Bool)),
58
59            address: mk(Elementary(Address(false))),
60            address_payable: mk(Elementary(Address(true))),
61
62            string,
63            string_ref: mk_refs(string),
64
65            bytes,
66            bytes_ref: mk_refs(bytes),
67
68            ints: from_fn(|i| mk(Elementary(Int(TypeSize::new_int_bits((i as u16 + 1) * 8))))),
69            uints: from_fn(|i| mk(Elementary(UInt(TypeSize::new_int_bits((i as u16 + 1) * 8))))),
70            fbs: from_fn(|i| mk(Elementary(FixedBytes(TypeSize::new_fb_bytes(i as u8 + 1))))),
71
72            __err_do_not_use: mk(Err(ErrorGuaranteed::new_unchecked())),
73        }
74    }
75
76    /// `int<bits>`.
77    #[inline]
78    #[track_caller]
79    pub fn int(&self, bits: u16) -> Ty<'gcx> {
80        self.int_(TypeSize::new_int_bits(bits))
81    }
82    /// `int<size>`.
83    #[inline]
84    pub fn int_(&self, size: TypeSize) -> Ty<'gcx> {
85        self.ints[size.bytes() as usize - 1]
86    }
87
88    /// `uint<bits>`.
89    #[inline]
90    #[track_caller]
91    pub fn uint(&self, bits: u16) -> Ty<'gcx> {
92        self.uint_(TypeSize::new_int_bits(bits))
93    }
94    /// `uint<size>`.
95    #[inline]
96    pub fn uint_(&self, size: TypeSize) -> Ty<'gcx> {
97        self.uints[size.bytes() as usize - 1]
98    }
99
100    /// `bytes<bytes>`.
101    #[inline]
102    #[track_caller]
103    pub fn fixed_bytes(&self, bytes: u8) -> Ty<'gcx> {
104        self.fixed_bytes_(TypeSize::new_fb_bytes(bytes))
105    }
106    /// `bytes<size>`.
107    #[inline]
108    pub fn fixed_bytes_(&self, size: TypeSize) -> Ty<'gcx> {
109        self.fbs[size.bytes() as usize - 1]
110    }
111}
112
113/// Holds an instance of `T` for each data location.
114pub struct EachDataLoc<T> {
115    pub storage: T,
116    pub transient: T,
117    pub memory: T,
118    pub calldata: T,
119}
120
121impl<T> EachDataLoc<T> {
122    /// Gets a copy for the given data location.
123    #[inline]
124    pub fn get(&self, loc: DataLocation) -> T
125    where
126        T: Copy,
127    {
128        match loc {
129            DataLocation::Storage => self.storage,
130            DataLocation::Transient => self.transient,
131            DataLocation::Memory => self.memory,
132            DataLocation::Calldata => self.calldata,
133        }
134    }
135
136    /// Gets a reference for the given data location.
137    #[inline]
138    pub fn get_ref(&self, loc: DataLocation) -> &T {
139        match loc {
140            DataLocation::Storage => &self.storage,
141            DataLocation::Transient => &self.transient,
142            DataLocation::Memory => &self.memory,
143            DataLocation::Calldata => &self.calldata,
144        }
145    }
146
147    /// Gets a mutable reference for the given data location.
148    #[inline]
149    pub fn get_mut(&mut self, loc: DataLocation) -> &mut T {
150        match loc {
151            DataLocation::Storage => &mut self.storage,
152            DataLocation::Transient => &mut self.transient,
153            DataLocation::Memory => &mut self.memory,
154            DataLocation::Calldata => &mut self.calldata,
155        }
156    }
157}
158
159impl<T> std::ops::Index<DataLocation> for EachDataLoc<T> {
160    type Output = T;
161
162    #[inline]
163    fn index(&self, loc: DataLocation) -> &Self::Output {
164        self.get_ref(loc)
165    }
166}
167
168impl<T> std::ops::IndexMut<DataLocation> for EachDataLoc<T> {
169    #[inline]
170    fn index_mut(&mut self, loc: DataLocation) -> &mut Self::Output {
171        self.get_mut(loc)
172    }
173}