1use crate::{
2 ast_lowering::resolve::{Declaration, Declarations},
3 hir,
4 ty::{Gcx, Ty, TyFnKind},
5};
6use solar_ast::StateMutability as SM;
7use solar_data_structures::map::FxHashMap;
8use solar_interface::{Span, Symbol, kw, sym};
9use std::sync::OnceLock;
10
11pub(crate) mod members;
12pub use members::{Member, MemberList};
13
14pub(crate) fn scopes() -> (Declarations, FxHashMap<Builtin, Declarations>) {
15 let global = declarations(Builtin::global());
16 let mut members_map = Builtin::iter()
17 .filter_map(|builtin| Some((builtin, declarations(builtin.members()?))))
18 .collect::<FxHashMap<_, _>>();
19 members_map.shrink_to_fit();
20 (global, members_map)
21}
22
23fn declarations(builtins: impl IntoIterator<Item = Builtin>) -> Declarations {
24 let mut declarations = Declarations::new();
25 for builtin in builtins {
26 let decl = Declaration { res: hir::Res::Builtin(builtin), span: Span::DUMMY };
27 declarations.declare_unchecked(builtin.name(), decl);
28 }
29 declarations
30}
31
32type Primitive = u8;
33
34macro_rules! declare_builtins {
35 (|$slf:ident, $gcx:ident| $($(#[$variant_attr:meta])* $variant_name:ident => $sym:ident::$name:ident => $ty:expr;)*) => {
36 #[repr(u8)]
38 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
39 pub enum Builtin {
40 $(
41 $(#[$variant_attr])*
42 $variant_name,
43 )*
44 }
45
46 impl Builtin {
47 pub const COUNT: usize = 0 $(+ { let _ = Builtin::$variant_name; 1 })*;
50
51 pub fn name(self) -> Symbol {
53 match self {
54 $(
55 Builtin::$variant_name => $sym::$name,
56 )*
57 }
58 }
59
60 pub fn ty<'gcx>($slf, $gcx: Gcx<'gcx>) -> Ty<'gcx> {
62 $gcx.type_of_builtin($slf)
63 }
64
65 pub(crate) fn ty_impl<'gcx>($slf, $gcx: Gcx<'gcx>) -> Ty<'gcx> {
66 match $slf {
67 $(
68 Builtin::$variant_name => $ty,
69 )*
70 }
71 }
72 }
73 };
74}
75
76declare_builtins! {
80 |self, gcx|
81
82 Blockhash => kw::Blockhash
84 => gcx.mk_builtin_fn(&[gcx.types.uint(256)], SM::View, &[gcx.types.fixed_bytes(32)]);
85 Blobhash => kw::Blobhash
86 => gcx.mk_builtin_fn(&[gcx.types.uint(256)], SM::View, &[gcx.types.fixed_bytes(32)]);
87
88 Gasleft => sym::gasleft
89 => gcx.mk_builtin_fn(&[], SM::View, &[gcx.types.uint(256)]);
90 Selfdestruct => kw::Selfdestruct
91 => gcx.mk_builtin_fn(&[gcx.types.address_payable], SM::NonPayable, &[]);
92
93 Assert => sym::assert
94 => gcx.mk_builtin_fn(&[gcx.types.bool], SM::Pure, &[]);
95 Require => sym::require
96 => gcx.mk_builtin_fn(&[gcx.types.bool, gcx.mk_ty_variadic()], SM::Pure, &[]);
97 Revert => kw::Revert
98 => gcx.mk_builtin_fn(&[], SM::Pure, &[]);
99 RevertMsg => kw::Revert
100 => gcx.mk_builtin_fn(&[gcx.types.string], SM::Pure, &[]);
101
102 AddMod => kw::Addmod
103 => gcx.mk_builtin_fn(&[gcx.types.uint(256), gcx.types.uint(256), gcx.types.uint(256)], SM::Pure, &[gcx.types.uint(256)]);
104 MulMod => kw::Mulmod
105 => gcx.mk_builtin_fn(&[gcx.types.uint(256), gcx.types.uint(256), gcx.types.uint(256)], SM::Pure, &[gcx.types.uint(256)]);
106
107 Keccak256 => kw::Keccak256
108 => gcx.mk_builtin_fn(&[gcx.types.bytes_ref.memory], SM::Pure, &[gcx.types.fixed_bytes(32)]);
109 Sha256 => sym::sha256
110 => gcx.mk_builtin_fn(&[gcx.types.bytes_ref.memory], SM::Pure, &[gcx.types.fixed_bytes(32)]);
111 Ripemd160 => sym::ripemd160
112 => gcx.mk_builtin_fn(&[gcx.types.bytes_ref.memory], SM::Pure, &[gcx.types.fixed_bytes(20)]);
113 EcRecover => sym::ecrecover
114 => 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]);
115
116 Erc7201 => sym::erc7201
117 => gcx.mk_builtin_fn(&[gcx.types.string_ref.memory], SM::Pure, &[gcx.types.uint(256)]);
118
119 Block => sym::block
120 => gcx.mk_builtin_mod(self);
121 Msg => sym::msg
122 => gcx.mk_builtin_mod(self);
123 Tx => sym::tx
124 => gcx.mk_builtin_mod(self);
125 Abi => sym::abi
126 => gcx.mk_builtin_mod(self);
127
128 This => sym::this => unreachable!();
130 Super => sym::super_ => unreachable!();
131
132 BlockCoinbase => kw::Coinbase
134 => gcx.types.address_payable;
135 BlockTimestamp => kw::Timestamp
136 => gcx.types.uint(256);
137 BlockDifficulty => kw::Difficulty
138 => gcx.types.uint(256);
139 BlockPrevrandao => kw::Prevrandao
140 => gcx.types.uint(256);
141 BlockNumber => kw::Number
142 => gcx.types.uint(256);
143 BlockGaslimit => kw::Gaslimit
144 => gcx.types.uint(256);
145 BlockChainid => kw::Chainid
146 => gcx.types.uint(256);
147 BlockBasefee => kw::Basefee
148 => gcx.types.uint(256);
149 BlockBlobbasefee => kw::Blobbasefee
150 => gcx.types.uint(256);
151
152 MsgSender => sym::sender
154 => gcx.types.address;
155 MsgGas => kw::Gas
156 => gcx.types.uint(256);
157 MsgValue => sym::value
158 => gcx.types.uint(256);
159 MsgData => sym::data
160 => gcx.types.bytes_ref.calldata;
161 MsgSig => sym::sig
162 => gcx.types.fixed_bytes(4);
163
164 TxOrigin => kw::Origin
166 => gcx.types.address;
167 TxGasPrice => kw::Gasprice
168 => gcx.types.uint(256);
169
170 AbiEncode => sym::encode
172 => gcx.mk_builtin_fn(&[gcx.mk_ty_variadic()], SM::Pure, &[gcx.types.bytes_ref.memory]);
173 AbiEncodePacked => sym::encodePacked
174 => gcx.mk_builtin_fn(&[gcx.mk_ty_variadic()], SM::Pure, &[gcx.types.bytes_ref.memory]);
175 AbiEncodeWithSelector => sym::encodeWithSelector
176 => gcx.mk_builtin_fn(&[gcx.types.fixed_bytes(4), gcx.mk_ty_variadic()], SM::Pure, &[gcx.types.bytes_ref.memory]);
177 AbiEncodeCall => sym::encodeCall
178 => gcx.mk_builtin_fn(&[gcx.mk_ty_variadic()], SM::Pure, &[gcx.types.bytes_ref.memory]);
179 AbiEncodeWithSignature => sym::encodeWithSignature
180 => gcx.mk_builtin_fn(&[gcx.types.string_ref.memory, gcx.mk_ty_variadic()], SM::Pure, &[gcx.types.bytes_ref.memory]);
181 AbiDecode => sym::decode
182 => gcx.mk_builtin_fn(&[gcx.types.bytes_ref.memory, gcx.mk_ty_tuple(gcx.mk_tys(&[gcx.mk_ty_variadic()]))], SM::Pure, &[gcx.mk_ty_variadic()]);
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_ty_fn_with_kind(TyFnKind::BareCall, &[gcx.types.bytes_ref.memory], SM::Payable, &[gcx.types.bool, gcx.types.bytes_ref.memory]);
194 AddressDelegatecall => kw::Delegatecall
195 => gcx.mk_ty_fn_with_kind(TyFnKind::BareDelegateCall, &[gcx.types.bytes_ref.memory], SM::NonPayable, &[gcx.types.bool, gcx.types.bytes_ref.memory]);
196 AddressStaticcall => kw::Staticcall
197 => gcx.mk_ty_fn_with_kind(TyFnKind::BareStaticCall, &[gcx.types.bytes_ref.memory], SM::View, &[gcx.types.bool, 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 ArrayPush0 => sym::push => unreachable!();
210 ArrayPush => sym::push => unreachable!();
211 ArrayPop => kw::Pop => unreachable!();
212
213 FunctionSelector => sym::selector
214 => gcx.types.fixed_bytes(4);
215
216 FunctionAddress => kw::Address
217 => gcx.types.address;
218
219 EventSelector => sym::selector
220 => gcx.types.fixed_bytes(32);
221
222 ContractCreationCode => sym::creationCode
224 => gcx.types.bytes_ref.memory;
225 ContractRuntimeCode => sym::runtimeCode
226 => gcx.types.bytes_ref.memory;
227 ContractName => sym::name
228 => gcx.types.string_ref.memory;
229 InterfaceId => sym::interfaceId
230 => gcx.types.fixed_bytes(4);
231 TypeMin => sym::min => unreachable!();
232 TypeMax => sym::max => unreachable!();
233
234 UdvtWrap => sym::wrap => unreachable!();
236 UdvtUnwrap => sym::unwrap => unreachable!();
237
238 StringConcat => sym::concat
239 => gcx.mk_builtin_fn(&[gcx.mk_ty_variadic()], SM::Pure, &[gcx.types.string_ref.memory]);
240
241 BytesConcat => sym::concat
242 => gcx.mk_builtin_fn(&[gcx.mk_ty_variadic()], SM::Pure, &[gcx.types.bytes_ref.memory]);
243
244 YulAdd => kw::Add => gcx.mk_yul_builtin_fn(2, 1);
246 YulSub => kw::Sub => gcx.mk_yul_builtin_fn(2, 1);
247 YulMul => kw::Mul => gcx.mk_yul_builtin_fn(2, 1);
248 YulDiv => kw::Div => gcx.mk_yul_builtin_fn(2, 1);
249 YulMod => kw::Mod => gcx.mk_yul_builtin_fn(2, 1);
250 YulExp => kw::Exp => gcx.mk_yul_builtin_fn(2, 1);
251 YulNot => kw::Not => gcx.mk_yul_builtin_fn(1, 1);
252 YulAnd => kw::And => gcx.mk_yul_builtin_fn(2, 1);
253 YulOr => kw::Or => gcx.mk_yul_builtin_fn(2, 1);
254 YulXor => kw::Xor => gcx.mk_yul_builtin_fn(2, 1);
255 YulShl => kw::Shl => gcx.mk_yul_builtin_fn(2, 1);
256 YulShr => kw::Shr => gcx.mk_yul_builtin_fn(2, 1);
257 YulSar => kw::Sar => gcx.mk_yul_builtin_fn(2, 1);
258 YulStop => kw::Stop => gcx.mk_yul_builtin_fn(0, 0);
259 YulSdiv => kw::Sdiv => gcx.mk_yul_builtin_fn(2, 1);
260 YulSmod => kw::Smod => gcx.mk_yul_builtin_fn(2, 1);
261 YulLt => kw::Lt => gcx.mk_yul_builtin_fn(2, 1);
262 YulGt => kw::Gt => gcx.mk_yul_builtin_fn(2, 1);
263 YulSlt => kw::Slt => gcx.mk_yul_builtin_fn(2, 1);
264 YulSgt => kw::Sgt => gcx.mk_yul_builtin_fn(2, 1);
265 YulEq => kw::Eq => gcx.mk_yul_builtin_fn(2, 1);
266 YulIszero => kw::Iszero => gcx.mk_yul_builtin_fn(1, 1);
267 YulByte => kw::Byte => gcx.mk_yul_builtin_fn(2, 1);
268 YulClz => kw::Clz => gcx.mk_yul_builtin_fn(1, 1);
269 YulAddmod => kw::Addmod => gcx.mk_yul_builtin_fn(3, 1);
270 YulMulmod => kw::Mulmod => gcx.mk_yul_builtin_fn(3, 1);
271 YulSignextend => kw::Signextend => gcx.mk_yul_builtin_fn(2, 1);
272 YulKeccak256 => kw::Keccak256 => gcx.mk_yul_builtin_fn(2, 1);
273 YulAddress => kw::Address => gcx.mk_yul_builtin_fn(0, 1);
274 YulBalance => kw::Balance => gcx.mk_yul_builtin_fn(1, 1);
275 YulSelfbalance => kw::Selfbalance => gcx.mk_yul_builtin_fn(0, 1);
276 YulCaller => kw::Caller => gcx.mk_yul_builtin_fn(0, 1);
277 YulCallvalue => kw::Callvalue => gcx.mk_yul_builtin_fn(0, 1);
278 YulCalldataload => kw::Calldataload => gcx.mk_yul_builtin_fn(1, 1);
279 YulCalldatasize => kw::Calldatasize => gcx.mk_yul_builtin_fn(0, 1);
280 YulCalldatacopy => kw::Calldatacopy => gcx.mk_yul_builtin_fn(3, 0);
281 YulCodesize => kw::Codesize => gcx.mk_yul_builtin_fn(0, 1);
282 YulCodecopy => kw::Codecopy => gcx.mk_yul_builtin_fn(3, 0);
283 YulExtcodesize => kw::Extcodesize => gcx.mk_yul_builtin_fn(1, 1);
284 YulExtcodecopy => kw::Extcodecopy => gcx.mk_yul_builtin_fn(4, 0);
285 YulReturndatasize => kw::Returndatasize => gcx.mk_yul_builtin_fn(0, 1);
286 YulReturndatacopy => kw::Returndatacopy => gcx.mk_yul_builtin_fn(3, 0);
287 YulExtcodehash => kw::Extcodehash => gcx.mk_yul_builtin_fn(1, 1);
288 YulMload => kw::Mload => gcx.mk_yul_builtin_fn(1, 1);
289 YulMstore => kw::Mstore => gcx.mk_yul_builtin_fn(2, 0);
290 YulMstore8 => kw::Mstore8 => gcx.mk_yul_builtin_fn(2, 0);
291 YulSload => kw::Sload => gcx.mk_yul_builtin_fn(1, 1);
292 YulSstore => kw::Sstore => gcx.mk_yul_builtin_fn(2, 0);
293 YulTload => kw::Tload => gcx.mk_yul_builtin_fn(1, 1);
294 YulTstore => kw::Tstore => gcx.mk_yul_builtin_fn(2, 0);
295 YulMsize => kw::Msize => gcx.mk_yul_builtin_fn(0, 1);
296 YulGas => kw::Gas => gcx.mk_yul_builtin_fn(0, 1);
297 YulLog0 => kw::Log0 => gcx.mk_yul_builtin_fn(2, 0);
298 YulLog1 => kw::Log1 => gcx.mk_yul_builtin_fn(3, 0);
299 YulLog2 => kw::Log2 => gcx.mk_yul_builtin_fn(4, 0);
300 YulLog3 => kw::Log3 => gcx.mk_yul_builtin_fn(5, 0);
301 YulLog4 => kw::Log4 => gcx.mk_yul_builtin_fn(6, 0);
302 YulCreate => kw::Create => gcx.mk_yul_builtin_fn(3, 1);
303 YulCreate2 => kw::Create2 => gcx.mk_yul_builtin_fn(4, 1);
304 YulCall => kw::Call => gcx.mk_yul_builtin_fn(7, 1);
305 YulCallcode => kw::Callcode => gcx.mk_yul_builtin_fn(7, 1);
306 YulDelegatecall => kw::Delegatecall => gcx.mk_yul_builtin_fn(6, 1);
307 YulStaticcall => kw::Staticcall => gcx.mk_yul_builtin_fn(6, 1);
308 YulExtcall => kw::Extcall => gcx.mk_yul_builtin_fn(4, 1);
309 YulExtdelegatecall => kw::Extdelegatecall => gcx.mk_yul_builtin_fn(3, 1);
310 YulExtstaticcall => kw::Extstaticcall => gcx.mk_yul_builtin_fn(3, 1);
311 YulReturn => kw::Return => gcx.mk_yul_builtin_fn(2, 0);
312 YulRevert => kw::Revert => gcx.mk_yul_builtin_fn(2, 0);
313 YulSelfdestruct => kw::Selfdestruct => gcx.mk_yul_builtin_fn(1, 0);
314 YulInvalid => kw::Invalid => gcx.mk_yul_builtin_fn(0, 0);
315 YulChainid => kw::Chainid => gcx.mk_yul_builtin_fn(0, 1);
316 YulBasefee => kw::Basefee => gcx.mk_yul_builtin_fn(0, 1);
317 YulBlobbasefee => kw::Blobbasefee => gcx.mk_yul_builtin_fn(0, 1);
318 YulBlobhash => kw::Blobhash => gcx.mk_yul_builtin_fn(1, 1);
319 YulCoinbase => kw::Coinbase => gcx.mk_yul_builtin_fn(0, 1);
320 YulDifficulty => kw::Difficulty => gcx.mk_yul_builtin_fn(0, 1);
321 YulPrevrandao => kw::Prevrandao => gcx.mk_yul_builtin_fn(0, 1);
322 YulGaslimit => kw::Gaslimit => gcx.mk_yul_builtin_fn(0, 1);
323 YulNumber => kw::Number => gcx.mk_yul_builtin_fn(0, 1);
324 YulTimestamp => kw::Timestamp => gcx.mk_yul_builtin_fn(0, 1);
325 YulGasprice => kw::Gasprice => gcx.mk_yul_builtin_fn(0, 1);
326 YulOrigin => kw::Origin => gcx.mk_yul_builtin_fn(0, 1);
327 YulBlockhash => kw::Blockhash => gcx.mk_yul_builtin_fn(1, 1);
328 YulPop => kw::Pop => gcx.mk_yul_builtin_fn(1, 0);
329 YulMcopy => kw::Mcopy => gcx.mk_yul_builtin_fn(3, 0);
330}
331
332impl Builtin {
333 const FIRST_GLOBAL: usize = 0;
334 const LAST_GLOBAL: usize = Self::Abi as usize + 1;
335
336 const FIRST_BLOCK: usize = Self::BlockCoinbase as usize;
337 const LAST_BLOCK: usize = Self::BlockBlobbasefee as usize + 1;
338
339 const FIRST_MSG: usize = Self::MsgSender as usize;
340 const LAST_MSG: usize = Self::MsgSig as usize + 1;
341
342 const FIRST_TX: usize = Self::TxOrigin as usize;
343 const LAST_TX: usize = Self::TxGasPrice as usize + 1;
344
345 const FIRST_ABI: usize = Self::AbiEncode as usize;
346 const LAST_ABI: usize = Self::AbiDecode as usize + 1;
347
348 const FIRST_YUL: usize = Self::YulAdd as usize;
349 const LAST_YUL: usize = Self::YulMcopy as usize + 1;
350
351 #[inline]
353 pub fn iter() -> std::iter::Map<std::ops::Range<usize>, impl FnMut(usize) -> Self> {
354 (0..Self::COUNT).map(|i| Self::from_index(i).unwrap())
355 }
356
357 #[inline]
358 const fn from_index(i: usize) -> Option<Self> {
359 const {
360 assert!(Self::COUNT <= Primitive::MAX as usize);
361 assert!(size_of::<Self>() == 1);
362 }
363 if i < Self::COUNT {
364 Some(unsafe { std::mem::transmute::<Primitive, Self>(i as Primitive) })
375 } else {
376 None
377 }
378 }
379
380 pub fn global() -> impl ExactSizeIterator<Item = Self> + Clone {
382 Self::make_range_iter(Self::FIRST_GLOBAL..Self::LAST_GLOBAL)
383 }
384
385 pub fn members(self) -> Option<impl ExactSizeIterator<Item = Self> + Clone> {
387 use Builtin::*;
388 Some(Self::make_range_iter(match self {
389 Block => Self::FIRST_BLOCK..Self::LAST_BLOCK,
390 Msg => Self::FIRST_MSG..Self::LAST_MSG,
391 Tx => Self::FIRST_TX..Self::LAST_TX,
392 Abi => Self::FIRST_ABI..Self::LAST_ABI,
393 _ => return None,
394 }))
395 }
396
397 pub fn from_yul_name(name: Symbol) -> Option<Self> {
399 static YUL_NAMES: OnceLock<FxHashMap<Symbol, Builtin>> = OnceLock::new();
400 YUL_NAMES
401 .get_or_init(|| {
402 Self::make_range_iter(Self::FIRST_YUL..Self::LAST_YUL)
403 .map(|builtin| (builtin.name(), builtin))
404 .collect()
405 })
406 .get(&name)
407 .copied()
408 }
409
410 #[inline]
411 fn make_range_iter(
412 range: std::ops::Range<usize>,
413 ) -> impl ExactSizeIterator<Item = Self> + Clone {
414 debug_assert!(range.start < Self::COUNT);
415 debug_assert!(range.end <= Self::COUNT);
416 (range.start as Primitive..range.end as Primitive)
417 .map(|idx| unsafe { Self::from_index(idx as usize).unwrap_unchecked() })
418 }
419}