1use super::{Interner, Ty, TyKind};
2use solar_ast::{DataLocation, ElementaryType, TypeSize};
3use solar_interface::diagnostics::ErrorGuaranteed;
4
5pub struct CommonTypes<'gcx> {
7 #[doc(alias = "empty_tuple", alias = "void")]
9 pub unit: Ty<'gcx>,
10 pub bool: Ty<'gcx>,
12
13 pub address: Ty<'gcx>,
15 pub address_payable: Ty<'gcx>,
17
18 pub string: Ty<'gcx>,
20 pub string_ref: EachDataLoc<Ty<'gcx>>,
22
23 pub bytes: Ty<'gcx>,
25 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 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 #[inline]
78 #[track_caller]
79 pub fn int(&self, bits: u16) -> Ty<'gcx> {
80 self.int_(TypeSize::new_int_bits(bits))
81 }
82 #[inline]
84 pub fn int_(&self, size: TypeSize) -> Ty<'gcx> {
85 self.ints[size.bytes() as usize - 1]
86 }
87
88 #[inline]
90 #[track_caller]
91 pub fn uint(&self, bits: u16) -> Ty<'gcx> {
92 self.uint_(TypeSize::new_int_bits(bits))
93 }
94 #[inline]
96 pub fn uint_(&self, size: TypeSize) -> Ty<'gcx> {
97 self.uints[size.bytes() as usize - 1]
98 }
99
100 #[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 #[inline]
108 pub fn fixed_bytes_(&self, size: TypeSize) -> Ty<'gcx> {
109 self.fbs[size.bytes() as usize - 1]
110 }
111}
112
113pub 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 #[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 #[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 #[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}