1use crate::{
2 ast_lowering::resolve::{Declaration, Declarations},
3 hir,
4 ty::{Gcx, Ty},
5};
6use solar_ast::StateMutability as SM;
7use solar_interface::{Span, Symbol, kw, sym};
8
9pub(crate) mod members;
10pub use members::{Member, MemberList};
11
12pub(crate) fn scopes() -> (Declarations, Box<[Option<Declarations>; Builtin::COUNT]>) {
13 let global = declarations(Builtin::global());
14 let members_map = Box::new(std::array::from_fn(|i| {
15 Some(declarations(Builtin::from_index(i).unwrap().members()?))
16 }));
17 (global, members_map)
18}
19
20fn declarations(builtins: impl IntoIterator<Item = Builtin>) -> Declarations {
21 let mut declarations = Declarations::new();
22 for builtin in builtins {
23 let decl = Declaration { res: hir::Res::Builtin(builtin), span: Span::DUMMY };
24 declarations.declare_unchecked(builtin.name(), decl);
25 }
26 declarations
27}
28
29type Primitive = u8;
30
31macro_rules! declare_builtins {
32 (|$gcx:ident| $($(#[$variant_attr:meta])* $variant_name:ident => $sym:ident::$name:ident => $ty:expr;)*) => {
33 #[repr(u8)]
35 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
36 pub enum Builtin {
37 $(
38 $(#[$variant_attr])*
39 $variant_name,
40 )*
41 }
42
43 impl Builtin {
44 pub const COUNT: usize = 0 $(+ { let _ = Builtin::$variant_name; 1 })*;
47
48 pub fn name(self) -> Symbol {
50 match self {
51 $(
52 Builtin::$variant_name => $sym::$name,
53 )*
54 }
55 }
56
57 pub fn ty(self, $gcx: Gcx<'_>) -> Ty<'_> {
59 match self {
60 $(
61 Builtin::$variant_name => $ty,
62 )*
63 }
64 }
65 }
66 };
67}
68
69declare_builtins! {
73 |gcx|
74
75 Blockhash => kw::Blockhash
77 => gcx.mk_builtin_fn(&[gcx.types.uint(256)], SM::View, &[gcx.types.fixed_bytes(32)]);
78 Blobhash => kw::Blobhash
79 => gcx.mk_builtin_fn(&[gcx.types.uint(256)], SM::View, &[gcx.types.fixed_bytes(32)]);
80
81 Gasleft => sym::gasleft
82 => gcx.mk_builtin_fn(&[], SM::View, &[gcx.types.uint(256)]);
83 Selfdestruct => kw::Selfdestruct
84 => gcx.mk_builtin_fn(&[gcx.types.address_payable], SM::NonPayable, &[]);
85
86 Assert => sym::assert
87 => gcx.mk_builtin_fn(&[gcx.types.bool], SM::Pure, &[]);
88 Require => sym::require
89 => gcx.mk_builtin_fn(&[gcx.types.bool], SM::Pure, &[]);
90 RequireMsg => sym::require
91 => gcx.mk_builtin_fn(&[gcx.types.bool, gcx.types.string_ref.memory], SM::Pure, &[]);
92 Revert => kw::Revert
95 => gcx.mk_builtin_fn(&[], SM::Pure, &[]);
96 RevertMsg => kw::Revert
97 => gcx.mk_builtin_fn(&[gcx.types.string], SM::Pure, &[]);
98
99 AddMod => kw::Addmod
100 => gcx.mk_builtin_fn(&[gcx.types.uint(256), gcx.types.uint(256), gcx.types.uint(256)], SM::Pure, &[gcx.types.uint(256)]);
101 MulMod => kw::Mulmod
102 => gcx.mk_builtin_fn(&[gcx.types.uint(256), gcx.types.uint(256), gcx.types.uint(256)], SM::Pure, &[gcx.types.uint(256)]);
103
104 Keccak256 => kw::Keccak256
105 => gcx.mk_builtin_fn(&[gcx.types.bytes_ref.memory], SM::Pure, &[gcx.types.fixed_bytes(32)]);
106 Sha256 => sym::sha256
107 => gcx.mk_builtin_fn(&[gcx.types.bytes_ref.memory], SM::Pure, &[gcx.types.fixed_bytes(32)]);
108 Ripemd160 => sym::ripemd160
109 => gcx.mk_builtin_fn(&[gcx.types.bytes_ref.memory], SM::Pure, &[gcx.types.fixed_bytes(20)]);
110 EcRecover => sym::ecrecover
111 => gcx.mk_builtin_fn(&[gcx.types.fixed_bytes(32), gcx.types.uint(8), gcx.types.fixed_bytes(32), gcx.types.fixed_bytes(32)], SM::Pure, &[gcx.types.address]);
112
113 Block => sym::block
114 => gcx.mk_builtin_mod(Self::Block);
115 Msg => sym::msg
116 => gcx.mk_builtin_mod(Self::Msg);
117 Tx => sym::tx
118 => gcx.mk_builtin_mod(Self::Tx);
119 Abi => sym::abi
120 => gcx.mk_builtin_mod(Self::Abi);
121
122 This => sym::this => unreachable!();
124 Super => sym::super_ => unreachable!();
125
126 BlockCoinbase => kw::Coinbase
128 => gcx.types.address_payable;
129 BlockTimestamp => kw::Timestamp
130 => gcx.types.uint(256);
131 BlockDifficulty => kw::Difficulty
132 => gcx.types.uint(256);
133 BlockPrevrandao => kw::Prevrandao
134 => gcx.types.uint(256);
135 BlockNumber => kw::Number
136 => gcx.types.uint(256);
137 BlockGaslimit => kw::Gaslimit
138 => gcx.types.uint(256);
139 BlockChainid => kw::Chainid
140 => gcx.types.uint(256);
141 BlockBasefee => kw::Basefee
142 => gcx.types.uint(256);
143 BlockBlobbasefee => kw::Blobbasefee
144 => gcx.types.uint(256);
145
146 MsgSender => sym::sender
148 => gcx.types.address;
149 MsgGas => kw::Gas
150 => gcx.types.uint(256);
151 MsgValue => sym::value
152 => gcx.types.uint(256);
153 MsgData => sym::data
154 => gcx.types.bytes_ref.calldata;
155 MsgSig => sym::sig
156 => gcx.types.fixed_bytes(4);
157
158 TxOrigin => kw::Origin
160 => gcx.types.address;
161 TxGasPrice => kw::Gasprice
162 => gcx.types.uint(256);
163
164 AbiEncode => sym::encode
167 => gcx.mk_builtin_fn(&[], SM::Pure, &[gcx.types.bytes_ref.memory]);
168 AbiEncodePacked => sym::encodePacked
170 => gcx.mk_builtin_fn(&[], SM::Pure, &[gcx.types.bytes_ref.memory]);
171 AbiEncodeWithSelector => sym::encodeWithSelector
173 => gcx.mk_builtin_fn(&[], SM::Pure, &[gcx.types.bytes_ref.memory]);
174 AbiEncodeCall => sym::encodeCall
176 => gcx.mk_builtin_fn(&[], SM::Pure, &[gcx.types.bytes_ref.memory]);
177 AbiEncodeWithSignature => sym::encodeWithSignature
179 => gcx.mk_builtin_fn(&[], SM::Pure, &[gcx.types.bytes_ref.memory]);
180 AbiDecode => sym::decode
182 => gcx.mk_builtin_fn(&[], SM::Pure, &[]);
183
184 AddressBalance => kw::Balance
187 => gcx.types.uint(256);
188 AddressCode => sym::code
189 => gcx.types.bytes_ref.memory;
190 AddressCodehash => sym::codehash
191 => gcx.types.fixed_bytes(32);
192 AddressCall => kw::Call
193 => gcx.mk_builtin_fn(&[gcx.types.bytes_ref.memory], SM::View, &[gcx.types.bytes_ref.memory]);
194 AddressDelegatecall => kw::Delegatecall
195 => gcx.mk_builtin_fn(&[gcx.types.bytes_ref.memory], SM::View, &[gcx.types.bytes_ref.memory]);
196 AddressStaticcall => kw::Staticcall
197 => gcx.mk_builtin_fn(&[gcx.types.bytes_ref.memory], SM::View, &[gcx.types.bytes_ref.memory]);
198
199 AddressPayableTransfer => sym::transfer
200 => gcx.mk_builtin_fn(&[gcx.types.uint(256)], SM::NonPayable, &[]);
201 AddressPayableSend => sym::send
202 => gcx.mk_builtin_fn(&[gcx.types.uint(256)], SM::NonPayable, &[gcx.types.bool]);
203
204 FixedBytesLength => sym::length
205 => gcx.types.uint(8);
206
207 ArrayLength => sym::length
208 => gcx.types.uint(256);
209
210 ErrorSelector => sym::selector
211 => gcx.types.fixed_bytes(4);
212
213 EventSelector => sym::selector
214 => gcx.types.fixed_bytes(32);
215
216 ContractCreationCode => sym::creationCode
218 => gcx.types.bytes_ref.memory;
219 ContractRuntimeCode => sym::runtimeCode
220 => gcx.types.bytes_ref.memory;
221 ContractName => sym::name
222 => gcx.types.string_ref.memory;
223 InterfaceId => sym::interfaceId
224 => gcx.types.fixed_bytes(4);
225 TypeMin => sym::min => unreachable!();
226 TypeMax => sym::max => unreachable!();
227
228 UdvtWrap => sym::wrap => unreachable!();
230 UdvtUnwrap => sym::unwrap => unreachable!();
231
232 StringConcat => sym::concat
234 => gcx.mk_builtin_fn(&[], SM::Pure, &[gcx.types.string_ref.memory]);
235
236 BytesConcat => sym::concat
238 => gcx.mk_builtin_fn(&[], SM::Pure, &[gcx.types.bytes_ref.memory]);
239}
240
241impl Builtin {
242 const FIRST_GLOBAL: usize = 0;
243 const LAST_GLOBAL: usize = Self::Abi as usize + 1;
244
245 const FIRST_BLOCK: usize = Self::BlockCoinbase as usize;
246 const LAST_BLOCK: usize = Self::BlockBlobbasefee as usize + 1;
247
248 const FIRST_MSG: usize = Self::MsgSender as usize;
249 const LAST_MSG: usize = Self::MsgSig as usize + 1;
250
251 const FIRST_TX: usize = Self::TxOrigin as usize;
252 const LAST_TX: usize = Self::TxGasPrice as usize + 1;
253
254 const FIRST_ABI: usize = Self::AbiEncode as usize;
255 const LAST_ABI: usize = Self::AbiDecode as usize + 1;
256
257 #[inline]
259 pub fn iter() -> std::iter::Map<std::ops::Range<usize>, impl FnMut(usize) -> Self> {
260 (0..Self::COUNT).map(|i| Self::from_index(i).unwrap())
261 }
262
263 #[inline]
264 const fn from_index(i: usize) -> Option<Self> {
265 const {
266 assert!(Self::COUNT <= Primitive::MAX as usize);
267 assert!(size_of::<Self>() == 1);
268 }
269 if i < Self::COUNT {
270 Some(unsafe { std::mem::transmute::<Primitive, Self>(i as Primitive) })
281 } else {
282 None
283 }
284 }
285
286 pub fn global() -> impl ExactSizeIterator<Item = Self> + Clone {
288 Self::make_range_iter(Self::FIRST_GLOBAL..Self::LAST_GLOBAL)
289 }
290
291 pub fn members(self) -> Option<impl ExactSizeIterator<Item = Self> + Clone> {
293 use Builtin::*;
294 Some(Self::make_range_iter(match self {
295 Block => Self::FIRST_BLOCK..Self::LAST_BLOCK,
296 Msg => Self::FIRST_MSG..Self::LAST_MSG,
297 Tx => Self::FIRST_TX..Self::LAST_TX,
298 Abi => Self::FIRST_ABI..Self::LAST_ABI,
299 _ => return None,
300 }))
301 }
302
303 #[inline]
304 fn make_range_iter(
305 range: std::ops::Range<usize>,
306 ) -> impl ExactSizeIterator<Item = Self> + Clone {
307 debug_assert!(range.start < Self::COUNT);
308 debug_assert!(range.end < Self::COUNT);
309 (range.start as Primitive..range.end as Primitive)
310 .map(|idx| unsafe { Self::from_index(idx as usize).unwrap_unchecked() })
311 }
312}