Skip to content

Commit 6371ac5

Browse files
committed
feat(slang): state-variable getters, custom errors, and type metadata
Adds the getter/ module synthesizing a getter `sol.func` for each public state variable off slang's getter type: scalar (value and reference) reads, keyed mapping/array levels (`sol.map` / `sol.gep` with `no_panic_bounds`), struct leaves with non-returnable members skipped, and constant initializer folds. External getter calls (`c.publicVar(keys)` -> static `sol.ext_call`) and `try` over a getter dispatch through the new `ExternalCallee` classification, which admits functions and public state variables alike. `require(cond, E(..))` lowers custom errors through `sol.require`; a contract namespace delegates value and place access to its members (`C.x = v`, `Library.CONST`); `type(..)` metadata folds to constants: integer min/max, name, interfaceId, and creation/runtime code through `sol.object_code`; error and event `.selector` fold to the selector and topic constants. Immutable and transient getters are loud `unimplemented!` arms. The slang pin moves to the rebased `az-dev-solx-clean`, whose `compute_interface_id` covers only the functions the interface itself declares, matching `type(I).interfaceId`.
1 parent 8e1a543 commit 6371ac5

34 files changed

Lines changed: 1368 additions & 146 deletions

Cargo.lock

Lines changed: 22 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,4 @@ features = [
9494
[workspace.dependencies.slang_solidity_v2]
9595
git = "https://github.com/NomicFoundation/slang.git"
9696
# TODO: pin to a release tag instead of a revision.
97-
rev = "c0c62aea7e0782bc21078450ae7d425699cda725"
97+
rev = "2640f3b1411a3eece9dbef4a3286a8f24b8dba45"

solx-mlir/src/context/function/dispatch.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//!
2-
//! The attribute a `sol.func` is reached through.
2+
//! The internal dispatch attribute a `sol.func` carries.
33
//!
44
55
use slang_solidity_v2::ast::FunctionDefinition;
@@ -8,14 +8,16 @@ use slang_solidity_v2::ast::NodeId;
88

99
use crate::FunctionKind;
1010

11-
/// The attribute a `sol.func` is reached through. A dispatch identifier is never zero, which the
12-
/// dialect reserves for the null function pointer, since slang numbers nodes from one.
11+
/// The internal dispatch attribute a `sol.func` carries, if any.
1312
#[derive(Clone, Copy)]
1413
pub enum FunctionDispatch {
15-
/// The identifier an internal function pointer dispatches to.
14+
/// The identifier an internal function pointer dispatches to; never zero, which the dialect
15+
/// reserves for the null function pointer, since slang numbers nodes from one.
1616
Identifier(NodeId),
1717
/// The dialect kind of a constructor, fallback or receive function.
1818
Kind(FunctionKind),
19+
/// A synthesized state-variable getter, dispatched by its ABI selector alone.
20+
Getter,
1921
}
2022

2123
impl From<&FunctionDefinition> for FunctionDispatch {

solx-mlir/src/context/function/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ impl<'context> Function<'context> {
9393
FunctionDispatch::Kind(function_kind) => {
9494
operation_builder.kind(function_kind.attribute(context.melior))
9595
}
96+
FunctionDispatch::Getter => operation_builder,
9697
};
9798
if let Some(selector_value) = selector {
9899
operation_builder = operation_builder

solx-mlir/src/ir/attributes.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ sol_dialect_attribute! {
4545
}
4646
}
4747

48+
impl StateMutability {
49+
/// Whether a callee of this mutability dispatches through a static call.
50+
pub fn is_static(self) -> bool {
51+
match self {
52+
Self::Pure | Self::View => true,
53+
Self::NonPayable | Self::Payable => false,
54+
}
55+
}
56+
}
57+
4858
impl From<FunctionMutability> for StateMutability {
4959
fn from(mutability: FunctionMutability) -> Self {
5060
match mutability {

solx-mlir/src/ir/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ sol_ops! {
157157
Value::code(address: value) -> value {
158158
CodeOperation.cont_addr(address).out(memory())
159159
}
160+
Value::object_code(object_name: str) -> value {
161+
ObjectCodeOperation.obj_name(str_attr(object_name)).out(memory())
162+
}
160163
Value::bare_call(address: value, gas: value, amount: value, input: value) -> values {
161164
BareCallOperation.addr(address).gas(gas).val(amount).inp(input)
162165
.status(boolean()).ret_data(memory())
@@ -265,9 +268,9 @@ sol_ops! {
265268
DeleteOperation.reference(self)
266269
}
267270

268-
Place::gep(self, index: value, element_type: ty) -> place {
271+
Place::gep | gep_no_panic_bounds (self, index: value, element_type: ty) -> place {
269272
GepOperation.base_addr(self).idx(index).addr(gep_of(element_type))
270-
}
273+
} flagged .no_panic_bounds;
271274
Place::map(self, key: value, entry_type: ty) -> place {
272275
MapOperation.mapping(self).key(key).addr(entry_type)
273276
}

solx-mlir/src/ir/type/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,12 @@ impl<'context> Type<'context> {
195195
IntegerType::try_from(self.inner).is_ok()
196196
}
197197

198-
/// The bit width of this integer type. Panics on a non-integer type, so a caller must first
199-
/// establish the type is an integer through [`Self::is_integer`].
198+
/// Whether this is a signed integer type.
199+
pub fn is_signed_integer(self) -> bool {
200+
IntegerType::try_from(self.inner).is_ok_and(|integer| integer.is_signed())
201+
}
202+
203+
/// The bit width of this integer type.
200204
pub fn integer_bit_width(self) -> u32 {
201205
IntegerType::try_from(self.inner)
202206
.expect("integer_bit_width called on a non-integer type")

solx-mlir/src/ir/value.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,26 @@ impl<'context> Value<'context> {
6464
Self::constant_from_bigint(&BigInt::one(), result_type, context)
6565
}
6666

67+
/// Materialises the smallest value the integer `result_type` admits: `type(T).min`.
68+
pub fn minimum(result_type: Type<'context>, context: &Context<'context>) -> Self {
69+
let value = if result_type.is_signed_integer() {
70+
-(BigInt::one() << (result_type.integer_bit_width() - 1))
71+
} else {
72+
BigInt::zero()
73+
};
74+
Self::constant_from_bigint(&value, result_type, context)
75+
}
76+
77+
/// Materialises the largest value the integer `result_type` admits: `type(T).max`.
78+
pub fn maximum(result_type: Type<'context>, context: &Context<'context>) -> Self {
79+
let value = if result_type.is_signed_integer() {
80+
(BigInt::one() << (result_type.integer_bit_width() - 1)) - 1
81+
} else {
82+
(BigInt::one() << result_type.integer_bit_width()) - 1
83+
};
84+
Self::constant_from_bigint(&value, result_type, context)
85+
}
86+
6787
/// Materialises an `i1` boolean constant.
6888
pub fn boolean(value: bool, context: &Context<'context>) -> Self {
6989
Self::constant(i64::from(value), Type::boolean(context.melior), context)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: solx --emit-mlir=sol %s | FileCheck %s
2+
3+
// Assignment to a contract-qualified state variable (C.x = v): solc's
4+
// print-init crashes (SIGSEGV), so this is solx-only.
5+
6+
// CHECK: sol.func @{{.*setNamespace.*}}
7+
// CHECK: %[[V:.*]] = sol.load %{{[0-9]+}} : !sol.ptr<ui256, Stack>, ui256
8+
// CHECK: %[[SLOT:.*]] = sol.addr_of @{{x.*}} : !sol.ptr<ui256, Storage>
9+
// CHECK: sol.store %[[V]], %[[SLOT]] : ui256, !sol.ptr<ui256, Storage>
10+
11+
contract C {
12+
uint256 x;
13+
14+
function setNamespace(uint256 v) public { C.x = v; }
15+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: solx --emit-mlir=sol %s | FileCheck %s
2+
3+
// Error and event .selector are compile-time constants: solc's print-init
4+
// crashes (SIGSEGV), so this is solx-only.
5+
6+
// CHECK: sol.func @{{.*error_selector.*}}
7+
// CHECK: sol.constant 816952677 : ui32
8+
// CHECK: sol.bytes_cast %{{.*}} : ui32 to !sol.fixedbytes<4>
9+
10+
// CHECK: sol.func @{{.*event_selector.*}}
11+
// CHECK: sol.constant 48926247962583432353061649299097379571640188309989729032230735130183305912964 : ui256
12+
// CHECK: sol.bytes_cast %{{.*}} : ui256 to !sol.fixedbytes<32>
13+
14+
error MyError(uint256 x);
15+
16+
contract C {
17+
event MyEvent(uint256 indexed a);
18+
19+
function error_selector() external pure returns (bytes4) {
20+
return MyError.selector;
21+
}
22+
23+
function event_selector() external pure returns (bytes32) {
24+
return MyEvent.selector;
25+
}
26+
}

0 commit comments

Comments
 (0)