Skip to content

Commit 24b943a

Browse files
committed
feat(slang): cast function call arguments to match parameter types
Store declared parameter types in function signatures and emit sol.cast for each argument whose type differs from the callee's declared parameter type. Also clean up inline melior:: paths across solx-slang by adding proper use imports.
1 parent d529afb commit 24b943a

8 files changed

Lines changed: 54 additions & 25 deletions

File tree

solx-mlir/src/context/function.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use melior::ir::Type;
99
pub struct Function<'context> {
1010
/// The mangled MLIR function name.
1111
pub mlir_name: String,
12-
/// Number of parameters.
13-
pub parameter_count: usize,
12+
/// Parameter types (MLIR-interned, exact types from the function signature).
13+
pub parameter_types: Vec<Type<'context>>,
1414
/// Return types (MLIR-interned, exact types from the function signature).
1515
pub return_types: Vec<Type<'context>>,
1616
}
@@ -19,12 +19,12 @@ impl<'context> Function<'context> {
1919
/// Creates a new function metadata entry.
2020
pub fn new(
2121
mlir_name: String,
22-
parameter_count: usize,
22+
parameter_types: Vec<Type<'context>>,
2323
return_types: Vec<Type<'context>>,
2424
) -> Self {
2525
Self {
2626
mlir_name,
27-
parameter_count,
27+
parameter_types,
2828
return_types,
2929
}
3030
}

solx-mlir/src/context/mod.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,18 +169,19 @@ impl<'context> Context<'context> {
169169
&mut self,
170170
bare_name: &str,
171171
mlir_name: String,
172-
parameter_count: usize,
172+
parameter_types: Vec<Type<'context>>,
173173
return_types: Vec<Type<'context>>,
174174
) {
175175
self.function_signatures
176176
.entry(bare_name.to_owned())
177177
.or_default()
178-
.push(Function::new(mlir_name, parameter_count, return_types));
178+
.push(Function::new(mlir_name, parameter_types, return_types));
179179
}
180180

181181
/// Resolves a function call by bare name and argument count.
182182
///
183-
/// Returns the mangled MLIR name and the declared return types.
183+
/// Returns the mangled MLIR name, declared parameter types, and return
184+
/// types.
184185
///
185186
/// # Errors
186187
///
@@ -189,19 +190,23 @@ impl<'context> Context<'context> {
189190
&self,
190191
bare_name: &str,
191192
argument_count: usize,
192-
) -> anyhow::Result<(&str, &[Type<'context>])> {
193+
) -> anyhow::Result<(&str, &[Type<'context>], &[Type<'context>])> {
193194
let signatures = self
194195
.function_signatures
195196
.get(bare_name)
196197
.ok_or_else(|| anyhow::anyhow!("undefined function: {bare_name}"))?;
197198
// TODO: resolve overloads by parameter types, not just arity
198199
let matches: Vec<_> = signatures
199200
.iter()
200-
.filter(|signature| signature.parameter_count == argument_count)
201+
.filter(|signature| signature.parameter_types.len() == argument_count)
201202
.collect();
202203
match matches.len() {
203204
0 => anyhow::bail!("no overload of '{bare_name}' takes {argument_count} arguments"),
204-
1 => Ok((matches[0].mlir_name.as_str(), &matches[0].return_types)),
205+
1 => Ok((
206+
matches[0].mlir_name.as_str(),
207+
&matches[0].parameter_types,
208+
&matches[0].return_types,
209+
)),
205210
_ => {
206211
let overloads: Vec<&str> = matches
207212
.iter()

solx-slang/src/ast/contract/function/expression/call/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,17 @@ impl<'emitter, 'state, 'context, 'block> CallEmitter<'emitter, 'state, 'context,
119119
current_block = next_block;
120120
}
121121

122-
let (mlir_name, return_types) = self
122+
let (mlir_name, parameter_types, return_types) = self
123123
.expression_emitter
124124
.state
125125
.resolve_function(&callee_name, argument_values.len())?;
126126

127+
// Cast arguments to match the callee's declared parameter types.
128+
let builder = &self.expression_emitter.state.builder;
129+
for (value, &param_type) in argument_values.iter_mut().zip(parameter_types) {
130+
*value = builder.emit_sol_cast(*value, param_type, &current_block);
131+
}
132+
127133
if return_types.is_empty() {
128134
self.expression_emitter.state.builder.emit_sol_call(
129135
mlir_name,

solx-slang/src/ast/contract/function/expression/call/type_conversion.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
//! Solidity type conversion classification and dispatch.
33
//!
44
5+
use melior::ir::BlockRef;
56
use melior::ir::Type;
7+
use melior::ir::Value;
68
use melior::ir::ValueLike;
79
use melior::ir::r#type::IntegerType;
10+
use melior::Context;
811
use slang_solidity::backend::ir::ast::Type as SlangType;
912

1013
/// Classification of Solidity type conversions.
@@ -24,7 +27,7 @@ impl<'context> TypeConversion<'context> {
2427
/// Maps a Slang semantic type to an MLIR type.
2528
pub fn resolve_slang_type(
2629
slang_type: &SlangType,
27-
context: &'context melior::Context,
30+
context: &'context Context,
2831
builder: &solx_mlir::Builder<'context>,
2932
) -> Type<'context> {
3033
match slang_type {
@@ -63,10 +66,10 @@ impl<'context> TypeConversion<'context> {
6366
/// Emits the conversion, returning the cast value.
6467
pub fn emit<'block>(
6568
self,
66-
value: melior::ir::Value<'context, 'block>,
69+
value: Value<'context, 'block>,
6770
builder: &solx_mlir::Builder<'context>,
68-
block: &melior::ir::BlockRef<'context, 'block>,
69-
) -> melior::ir::Value<'context, 'block>
71+
block: &BlockRef<'context, 'block>,
72+
) -> Value<'context, 'block>
7073
where
7174
'context: 'block,
7275
{
@@ -77,7 +80,7 @@ impl<'context> TypeConversion<'context> {
7780
}
7881
Self::Address => {
7982
let address_type = builder.types.sol_address;
80-
let truncated = if melior::ir::r#type::IntegerType::try_from(value.r#type()).is_ok()
83+
let truncated = if IntegerType::try_from(value.r#type()).is_ok()
8184
{
8285
let ui160 = builder.types.ui160;
8386
builder.emit_sol_cast(value, ui160, block)

solx-slang/src/ast/contract/function/expression/operator.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::str::FromStr;
77
use melior::ir::Location;
88
use melior::ir::Value;
99
use melior::ir::operation::Operation;
10+
use melior::Context;
1011

1112
use solx_mlir::CmpPredicate;
1213
use solx_mlir::ods::sol::AddOperation;
@@ -130,7 +131,7 @@ impl Operator {
130131
pub fn emit_sol_binary_operation<'context>(
131132
self,
132133
checked: bool,
133-
context: &'context melior::Context,
134+
context: &'context Context,
134135
location: Location<'context>,
135136
lhs: Value<'context, '_>,
136137
rhs: Value<'context, '_>,

solx-slang/src/ast/contract/function/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ use std::collections::HashMap;
99
use std::rc::Rc;
1010

1111
use melior::ir::BlockLike;
12+
use melior::ir::BlockRef;
1213
use melior::ir::Type;
14+
use melior::ir::Value;
1315
use slang_solidity::backend::SemanticAnalysis;
1416
use slang_solidity::backend::abi::AbiEntry;
1517
use slang_solidity::backend::ir::ast::ElementaryType;
@@ -64,7 +66,7 @@ impl<'state, 'context> FunctionEmitter<'state, 'context> {
6466
pub fn emit_sol(
6567
&self,
6668
function: &FunctionDefinition,
67-
contract_body: &melior::ir::BlockRef<'context, '_>,
69+
contract_body: &BlockRef<'context, '_>,
6870
) -> anyhow::Result<String> {
6971
let Some(ref body) = function.body() else {
7072
// Abstract or interface function — no codegen needed.
@@ -133,7 +135,7 @@ impl<'state, 'context> FunctionEmitter<'state, 'context> {
133135
.map(|id| id.name())
134136
.unwrap_or_else(|| "_".to_owned());
135137
let parameter_type = mlir_parameter_types[index];
136-
let parameter_value: melior::ir::Value<'context, '_> =
138+
let parameter_value: Value<'context, '_> =
137139
function_entry_block.argument(index)?.into();
138140
let pointer = self
139141
.state
@@ -259,7 +261,7 @@ impl<'state, 'context> FunctionEmitter<'state, 'context> {
259261
fn emit_default_return(
260262
&self,
261263
result_types: &[Type<'context>],
262-
block: &melior::ir::BlockRef<'context, '_>,
264+
block: &BlockRef<'context, '_>,
263265
) {
264266
if block.terminator().is_some() {
265267
return;

solx-slang/src/ast/contract/function/statement/control_flow.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
//! Control flow statement lowering: if/else, for, while, do-while.
33
//!
44
5+
use melior::ir::Block;
56
use melior::ir::BlockRef;
7+
use melior::ir::Region;
68
use melior::ir::RegionLike;
79

810
use slang_solidity::backend::ir::ast::ForStatementCondition;
@@ -257,8 +259,8 @@ impl<'state, 'context, 'block> StatementEmitter<'state, 'context, 'block> {
257259
/// Appends a dead block with `sol.yield` to a region whose live block
258260
/// already terminated (e.g. with `sol.return`). Matches the solc pattern
259261
/// where each `sol.if` region always ends with a `sol.yield` block.
260-
fn emit_dead_yield(&self, region: &melior::ir::Region<'context>) {
261-
let dead_block = melior::ir::Block::new(&[]);
262+
fn emit_dead_yield(&self, region: &Region<'context>) {
263+
let dead_block = Block::new(&[]);
262264
self.state.builder.emit_sol_yield(&dead_block);
263265
region.append_block(dead_block);
264266
}

solx-slang/src/ast/contract/mod.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,18 @@ impl<'state, 'context> ContractEmitter<'state, 'context> {
107107
}
108108
let name = FunctionEmitter::mlir_base_name(&function);
109109
let mlir_name = FunctionEmitter::mlir_function_name(&function);
110-
let parameter_count = function.parameters().len();
111-
let return_types: Vec<melior::ir::Type<'_>> = function
110+
let parameter_types = function
111+
.parameters()
112+
.iter()
113+
.map(|param| {
114+
TypeConversion::resolve_slang_type(
115+
&param.get_type().expect("parameter type binding resolved"),
116+
self.state.builder.context,
117+
&self.state.builder,
118+
)
119+
})
120+
.collect();
121+
let return_types = function
112122
.returns()
113123
.map(|returns| {
114124
returns
@@ -125,7 +135,7 @@ impl<'state, 'context> ContractEmitter<'state, 'context> {
125135
.unwrap_or_default();
126136

127137
self.state
128-
.register_function_signature(&name, mlir_name, parameter_count, return_types);
138+
.register_function_signature(&name, mlir_name, parameter_types, return_types);
129139
}
130140
}
131141

0 commit comments

Comments
 (0)