Skip to content

Commit

Permalink
fix: add missing builtins (#96)
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes authored Oct 30, 2024
1 parent 76a6d9a commit 07cbe85
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 144 deletions.
2 changes: 1 addition & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
xtask = "run --package xtask --bin xtask --"
tq = "xtask test"
qt = "tq"
ryul = "run --package solar --bin solar -- --language yul -Zparse-yul"
ryul = "run --package solar-compiler --bin solar -- --language yul -Zparse-yul"
bless = "xtask test --bless"
uitest = "xtask test ui"
uibless = "xtask test ui --bless"
1 change: 1 addition & 0 deletions crates/interface/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,7 @@ symbols! {
error,
experimental,
from,
gasleft,
global,
interfaceId,
length,
Expand Down
32 changes: 16 additions & 16 deletions crates/sema/src/builtins/members.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ use solar_ast::ast::{DataLocation, ElementaryType, StateMutability as SM};
use solar_data_structures::BumpExt;
use solar_interface::{kw, sym, Symbol};

pub type MemberMap<'gcx> = &'gcx [Member<'gcx>];
pub(crate) type MemberMapOwned<'gcx> = Vec<Member<'gcx>>;
pub type MemberList<'gcx> = &'gcx [Member<'gcx>];
pub(crate) type MemberListOwned<'gcx> = Vec<Member<'gcx>>;

pub(crate) fn members_of<'gcx>(gcx: Gcx<'gcx>, ty: Ty<'gcx>) -> MemberMap<'gcx> {
pub(crate) fn members_of<'gcx>(gcx: Gcx<'gcx>, ty: Ty<'gcx>) -> MemberList<'gcx> {
let expected_ref = || unreachable!("members_of: type {ty:?} should be wrapped in Ref");
gcx.bump().alloc_vec(match ty.kind {
TyKind::Elementary(elementary_type) => match elementary_type {
Expand Down Expand Up @@ -81,7 +81,7 @@ impl<'gcx> Member<'gcx> {
pub fn of_builtins(
gcx: Gcx<'gcx>,
builtins: impl IntoIterator<Item = Builtin>,
) -> MemberMapOwned<'gcx> {
) -> MemberListOwned<'gcx> {
Self::of_builtins_iter(gcx, builtins).collect()
}

Expand Down Expand Up @@ -114,14 +114,14 @@ fn address_payable(gcx: Gcx<'_>) -> impl Iterator<Item = Member<'_>> {
))
}

fn fixed_bytes(gcx: Gcx<'_>) -> MemberMapOwned<'_> {
fn fixed_bytes(gcx: Gcx<'_>) -> MemberListOwned<'_> {
Member::of_builtins(gcx, [Builtin::FixedBytesLength])
}

pub(crate) fn contract(gcx: Gcx<'_>, id: hir::ContractId) -> MemberMapOwned<'_> {
pub(crate) fn contract(gcx: Gcx<'_>, id: hir::ContractId) -> MemberListOwned<'_> {
let c = gcx.hir.contract(id);
if c.kind.is_library() {
return MemberMapOwned::default();
return MemberListOwned::default();
}
gcx.interface_functions(id)
.all_functions()
Expand All @@ -133,7 +133,7 @@ pub(crate) fn contract(gcx: Gcx<'_>, id: hir::ContractId) -> MemberMapOwned<'_>
.collect()
}

fn function<'gcx>(gcx: Gcx<'gcx>, f: &'gcx TyFnPtr<'gcx>) -> MemberMapOwned<'gcx> {
fn function<'gcx>(gcx: Gcx<'gcx>, f: &'gcx TyFnPtr<'gcx>) -> MemberListOwned<'gcx> {
let _ = (gcx, f);
todo!()
}
Expand All @@ -143,7 +143,7 @@ fn reference<'gcx>(
this: Ty<'gcx>,
inner: Ty<'gcx>,
loc: DataLocation,
) -> MemberMapOwned<'gcx> {
) -> MemberListOwned<'gcx> {
match (&inner.kind, loc) {
(&TyKind::Struct(id), _) => {
let fields = gcx.hir.strukt(id).fields;
Expand Down Expand Up @@ -180,7 +180,7 @@ fn reference<'gcx>(
}

// `Enum.Variant`, `Udvt.wrap`
fn type_type<'gcx>(gcx: Gcx<'gcx>, ty: Ty<'gcx>) -> MemberMapOwned<'gcx> {
fn type_type<'gcx>(gcx: Gcx<'gcx>, ty: Ty<'gcx>) -> MemberListOwned<'gcx> {
match ty.kind {
// TODO: https://github.com/ethereum/solidity/blob/9d7cc42bc1c12bb43e9dccf8c6c36833fdfcbbca/libsolidity/ast/Types.cpp#L3913
TyKind::Contract(_) => Default::default(),
Expand All @@ -206,7 +206,7 @@ fn type_type<'gcx>(gcx: Gcx<'gcx>, ty: Ty<'gcx>) -> MemberMapOwned<'gcx> {
}

// `type(T)`
fn meta<'gcx>(gcx: Gcx<'gcx>, ty: Ty<'gcx>) -> MemberMapOwned<'gcx> {
fn meta<'gcx>(gcx: Gcx<'gcx>, ty: Ty<'gcx>) -> MemberListOwned<'gcx> {
match ty.kind {
TyKind::Contract(id) => {
if gcx.hir.contract(id).can_be_deployed() {
Expand All @@ -225,25 +225,25 @@ fn meta<'gcx>(gcx: Gcx<'gcx>, ty: Ty<'gcx>) -> MemberMapOwned<'gcx> {
}
}

fn array(gcx: Gcx<'_>) -> MemberMapOwned<'_> {
fn array(gcx: Gcx<'_>) -> MemberListOwned<'_> {
Member::of_builtins(gcx, [Builtin::ArrayLength])
}

fn string_ty(gcx: Gcx<'_>) -> MemberMapOwned<'_> {
fn string_ty(gcx: Gcx<'_>) -> MemberListOwned<'_> {
Member::of_builtins(gcx, [Builtin::StringConcat])
}

fn bytes_ty(gcx: Gcx<'_>) -> MemberMapOwned<'_> {
fn bytes_ty(gcx: Gcx<'_>) -> MemberListOwned<'_> {
Member::of_builtins(gcx, [Builtin::BytesConcat])
}

fn type_contract(gcx: Gcx<'_>) -> MemberMapOwned<'_> {
fn type_contract(gcx: Gcx<'_>) -> MemberListOwned<'_> {
Member::of_builtins(
gcx,
[Builtin::ContractCreationCode, Builtin::ContractRuntimeCode, Builtin::ContractName],
)
}

fn type_interface(gcx: Gcx<'_>) -> MemberMapOwned<'_> {
fn type_interface(gcx: Gcx<'_>) -> MemberListOwned<'_> {
Member::of_builtins(gcx, [Builtin::InterfaceId, Builtin::ContractName])
}
98 changes: 70 additions & 28 deletions crates/sema/src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use solar_ast::ast::StateMutability as SM;
use solar_interface::{kw, sym, Span, Symbol};

pub(crate) mod members;
pub use members::{Member, MemberMap};
pub use members::{Member, MemberList};

pub(crate) fn scopes() -> (Declarations, Box<[Option<Declarations>; Builtin::COUNT]>) {
let global = declarations(Builtin::global().iter().copied());
Expand Down Expand Up @@ -70,10 +70,15 @@ declare_builtins! {
Blobhash => kw::Blobhash
=> gcx.mk_builtin_fn(&[gcx.types.uint(256)], SM::View, &[gcx.types.fixed_bytes(32)]);

Gasleft => sym::gasleft
=> gcx.mk_builtin_fn(&[], SM::View, &[gcx.types.uint(256)]);

Assert => sym::assert
=> gcx.mk_builtin_fn(&[gcx.types.bool], SM::Pure, &[]);
Require => sym::require
=> gcx.mk_builtin_fn(&[gcx.types.bool], SM::Pure, &[]);
RequireMsg => sym::require
=> gcx.mk_builtin_fn(&[gcx.types.bool, gcx.types.string_ref.memory], SM::Pure, &[]);
Revert => kw::Revert
=> gcx.mk_builtin_fn(&[], SM::Pure, &[]);
RevertMsg => kw::Revert
Expand Down Expand Up @@ -102,6 +107,7 @@ declare_builtins! {
Abi => sym::abi
=> gcx.mk_builtin_mod(Self::Abi);

// Contract
This => sym::this => unreachable!();
Super => sym::super_ => unreachable!();

Expand Down Expand Up @@ -220,57 +226,93 @@ declare_builtins! {
=> gcx.mk_builtin_fn(&[], SM::Pure, &[gcx.types.bytes_ref.memory]);
}

/// `$first..$last` as a slice of builtins.
macro_rules! builtin_range_slice {
($first:expr, $last:expr) => {
&const {
let mut i = $first;
let mut out = [Builtin::Blockhash; $last - $first];
while i < $last {
out[i - $first] = Builtin::from_index_unwrap(i);
i += 1;
}
out
}
};
}

impl Builtin {
const FIRST_GLOBAL: usize = 0;
const LAST_GLOBAL: usize = Self::Abi as usize + 1;

const FIRST_BLOCK: usize = Self::BlockCoinbase as usize;
const LAST_BLOCK: usize = Self::BlockBlobbasefee as usize + 1;

const FIRST_MSG: usize = Self::MsgSender as usize;
const LAST_MSG: usize = Self::MsgSig as usize + 1;

const FIRST_TX: usize = Self::TxOrigin as usize;
const LAST_TX: usize = Self::TxGasPrice as usize + 1;

const FIRST_ABI: usize = Self::AbiEncode as usize;
const LAST_ABI: usize = Self::AbiDecode as usize + 1;

/// Returns an iterator over all builtins.
#[inline]
pub fn iter() -> std::iter::Map<std::ops::Range<usize>, impl FnMut(usize) -> Self> {
(0..Self::COUNT).map(|i| Self::from_index(i).unwrap())
}

#[inline]
fn from_index(i: usize) -> Option<Self> {
const fn from_index(i: usize) -> Option<Self> {
const {
assert!(Self::COUNT <= u8::MAX as usize);
assert!(std::mem::size_of::<Self>() == 1);
};
if i < Self::COUNT {
Some(unsafe { std::mem::transmute::<u8, Self>(i as u8) })
} else {
None
}
}

// TODO(MSRV-1.83): Replace with .unwrap()
#[inline]
const fn from_index_unwrap(i: usize) -> Self {
match Self::from_index(i) {
Some(b) => b,
None => panic!(),
}
}

/// Returns the global builtins.
pub fn global() -> &'static [Self] {
use Builtin::*;
&[
Blockhash, Blobhash, Assert, Require, Revert, RevertMsg, AddMod, MulMod, Keccak256,
Sha256, Ripemd160, EcRecover, Block, Msg, Tx, Abi,
]
builtin_range_slice!(Self::FIRST_GLOBAL, Self::LAST_GLOBAL)
}

/// Returns the inner builtins.
pub fn inner(self) -> Option<&'static [Self]> {
use Builtin::*;
Some(match self {
Block => &[
BlockCoinbase,
BlockTimestamp,
BlockDifficulty,
BlockPrevrandao,
BlockNumber,
BlockGaslimit,
BlockChainid,
BlockBasefee,
BlockBlobbasefee,
],
Msg => &[MsgSender, MsgGas, MsgValue, MsgData, MsgSig],
Tx => &[TxOrigin, TxGasPrice],
Abi => &[
AbiEncode,
AbiEncodePacked,
AbiEncodeWithSelector,
AbiEncodeCall,
AbiEncodeWithSignature,
AbiDecode,
],
Block => builtin_range_slice!(Self::FIRST_BLOCK, Self::LAST_BLOCK),
Msg => builtin_range_slice!(Self::FIRST_MSG, Self::LAST_MSG),
Tx => builtin_range_slice!(Self::FIRST_TX, Self::LAST_TX),
Abi => builtin_range_slice!(Self::FIRST_ABI, Self::LAST_ABI),
_ => return None,
})
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn slice() {
let slice = builtin_range_slice!(0, 3);
assert_eq!(slice.len(), 3);
assert_eq!(slice[0] as usize, 0);
assert_eq!(slice[1] as usize, 1);
assert_eq!(slice[2] as usize, 2);
}
}
22 changes: 10 additions & 12 deletions crates/sema/src/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use crate::{
ast_lowering::SymbolResolver,
builtins::{
members::{self, MemberMap},
Builtin,
},
builtins::{members, Builtin},
hir::{self, Hir},
};
use alloy_primitives::{keccak256, Selector, B256};
Expand Down Expand Up @@ -156,6 +153,10 @@ impl<'gcx> Gcx<'gcx> {
self.interner.intern_ty_iter(tys)
}

fn mk_item_tys<T: Into<hir::ItemId> + Copy>(self, ids: &[T]) -> &'gcx [Ty<'gcx>] {
self.mk_ty_iter(ids.iter().map(|&id| self.type_of_item(id.into())))
}

pub fn mk_ty_string_literal(self, s: &[u8]) -> Ty<'gcx> {
self.mk_ty(TyKind::StringLiteral(
std::str::from_utf8(s).is_ok(),
Expand Down Expand Up @@ -520,9 +521,8 @@ pub fn type_of_item(gcx: _, id: hir::ItemId) -> Ty<'gcx> {
hir::ItemId::Function(id) => {
let f = gcx.hir.function(id);
TyKind::FnPtr(gcx.interner.intern_ty_fn_ptr(TyFnPtr {
parameters:
gcx.mk_ty_iter(f.parameters.iter().map(|&var| gcx.type_of_item(var.into()))),
returns: gcx.mk_ty_iter(f.returns.iter().map(|&var| gcx.type_of_item(var.into()))),
parameters: gcx.mk_item_tys(f.parameters),
returns: gcx.mk_item_tys(f.returns),
state_mutability: f.state_mutability,
visibility: f.visibility,
}))
Expand Down Expand Up @@ -553,12 +553,10 @@ pub fn type_of_item(gcx: _, id: hir::ItemId) -> Ty<'gcx> {
}
}
hir::ItemId::Error(id) => {
let tys = gcx.hir.error(id).parameters.iter().map(|&p| gcx.type_of_item(p.into()));
TyKind::Error(gcx.mk_ty_iter(tys), id)
TyKind::Error(gcx.mk_item_tys(gcx.hir.error(id).parameters), id)
}
hir::ItemId::Event(id) => {
let tys = gcx.hir.event(id).parameters.iter().map(|&p| gcx.type_of_item(p.into()));
TyKind::Event(gcx.mk_ty_iter(tys), id)
TyKind::Event(gcx.mk_item_tys(gcx.hir.event(id).parameters), id)
}
};
gcx.mk_ty(kind)
Expand All @@ -570,7 +568,7 @@ pub fn struct_field_types(gcx: _, id: hir::StructId) -> &'gcx [Ty<'gcx>] {
}

/// Returns the members of the given type.
pub fn members_of(gcx: _, ty: Ty<'gcx>) -> MemberMap<'gcx> {
pub fn members_of(gcx: _, ty: Ty<'gcx>) -> members::MemberList<'gcx> {
members::members_of(gcx, ty)
}
}
Expand Down
6 changes: 3 additions & 3 deletions crates/sema/src/typeck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use solar_data_structures::{map::FxHashSet, parallel};
pub(crate) fn check(gcx: Gcx<'_>) {
parallel!(
gcx.sess,
gcx.hir.par_source_ids().for_each(|id| {
check_duplicate_definitions(gcx, &gcx.symbol_resolver.source_scopes[id]);
}),
gcx.hir.par_contract_ids().for_each(|id| {
check_duplicate_definitions(gcx, &gcx.symbol_resolver.contract_scopes[id]);
}),
gcx.hir.par_source_ids().for_each(|id| {
check_duplicate_definitions(gcx, &gcx.symbol_resolver.source_scopes[id]);
}),
);
}

Expand Down
Loading

0 comments on commit 07cbe85

Please sign in to comment.