diff --git a/Cargo.toml b/Cargo.toml index cc85bca35..4a866802a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ license = "Apache-2.0" build = "build.rs" description = "Solang Solidity Compiler" keywords = [ "solidity", "compiler", "solana", "polkadot", "substrate" ] -rust-version = "1.85.0" +rust-version = "1.87" edition = "2021" exclude = [ "/.*", "/docs", "/solana-library", "/tests", "/integration", "/vscode", "/testdata" ] @@ -72,6 +72,7 @@ solang-forge-fmt = { version = "0.2.0", optional = true } # build to work. ethers-core = { version = "2.0.10", optional = true } soroban-sdk = { version = "23.0.0-rc.2.2", features = ["testutils"], optional = true } +miden-vm = "=0.16.0" [dev-dependencies] num-derive = "0.4" diff --git a/src/bin/cli/mod.rs b/src/bin/cli/mod.rs index 67839d9a2..a63bf29f8 100644 --- a/src/bin/cli/mod.rs +++ b/src/bin/cli/mod.rs @@ -273,7 +273,7 @@ pub struct TargetArg { #[derive(Args, Deserialize, Debug, PartialEq)] pub struct CompileTargetArg { - #[arg(name = "TARGET", long = "target", value_parser = ["solana", "polkadot", "evm", "soroban"], help = "Target to build for [possible values: solana, polkadot]", num_args = 1, hide_possible_values = true)] + #[arg(name = "TARGET", long = "target", value_parser = ["solana", "polkadot", "evm", "soroban", "miden"], help = "Target to build for [possible values: solana, polkadot]", num_args = 1, hide_possible_values = true)] pub name: Option, #[arg(name = "ADDRESS_LENGTH", help = "Address length on the Polkadot Parachain", long = "address-length", num_args = 1, value_parser = value_parser!(u64).range(4..1024))] @@ -469,6 +469,7 @@ pub(crate) fn target_arg(target_arg: &T) -> Target { }, "evm" => solang::Target::EVM, "soroban" => solang::Target::Soroban, + "miden" => solang::Target::Miden, _ => unreachable!(), }; diff --git a/src/codegen/cfg.rs b/src/codegen/cfg.rs index 923f64aa8..971df77ab 100644 --- a/src/codegen/cfg.rs +++ b/src/codegen/cfg.rs @@ -423,6 +423,12 @@ pub struct ControlFlowGraph { pub array_lengths_temps: ArrayLengthVars, /// Is this a modifier dispatch for which function number? pub modifier: Option, + + // POC(miden): mimic the miden target stack + pub miden_stack: Vec, + + // POC(miden): hold the miden instructions + pub miden_instrs: Vec, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -495,6 +501,8 @@ impl ControlFlowGraph { current: 0, array_lengths_temps: IndexMap::new(), modifier: None, + miden_stack: Vec::new(), + miden_instrs: Vec::new(), }; cfg.new_basic_block("entry".to_string()); @@ -518,6 +526,8 @@ impl ControlFlowGraph { current: 0, array_lengths_temps: IndexMap::new(), modifier: None, + miden_stack: Vec::new(), + miden_instrs: Vec::new(), } } @@ -622,6 +632,16 @@ impl ControlFlowGraph { } } + /// POC(miden): Push value to miden stack + pub fn push_to_miden_stack(&mut self, value: String) { + self.miden_instrs.push(format!(" push.{}", value)); + } + + /// POC(miden): Push instr to miden instrs + pub fn push_miden_instr(&mut self, instr: String) { + self.miden_instrs.push(format!(" {}", instr)); + } + pub fn expr_to_string(&self, contract: &Contract, ns: &Namespace, expr: &Expression) -> String { match expr { Expression::FunctionArg { arg_no, .. } => format!("(arg #{arg_no})"), @@ -1819,6 +1839,10 @@ fn function_cfg( None => pt::Loc::Codegen, }; // add implicit return + + // POC(Miden): for miden, the return instr returns the data on the stack + cfg.push_miden_instr("exec.sys::truncate_stack".to_string()); + cfg.add( &mut vartab, Instr::Return { diff --git a/src/codegen/dispatch/mod.rs b/src/codegen/dispatch/mod.rs index be718d9ec..5c89a0760 100644 --- a/src/codegen/dispatch/mod.rs +++ b/src/codegen/dispatch/mod.rs @@ -19,5 +19,6 @@ pub(super) fn function_dispatch( polkadot::function_dispatch(contract_no, all_cfg, ns, opt) } Target::Soroban => soroban::function_dispatch(contract_no, all_cfg, ns, opt), + Target::Miden => Vec::new(), } } diff --git a/src/codegen/events/mod.rs b/src/codegen/events/mod.rs index 43e00e064..6c2fa7db3 100644 --- a/src/codegen/events/mod.rs +++ b/src/codegen/events/mod.rs @@ -51,6 +51,6 @@ pub(super) fn new_event_emitter<'a>( event_no, }), - Target::Soroban => todo!(), + Target::Soroban | Target::Miden => todo!(), } } diff --git a/src/codegen/expression.rs b/src/codegen/expression.rs index 25a7c961b..a3ec87d8d 100644 --- a/src/codegen/expression.rs +++ b/src/codegen/expression.rs @@ -1327,6 +1327,11 @@ fn post_incdec( if ns.target == Target::Soroban { value = soroban_encode_arg(value, cfg, vartab, ns); } + // Poc(miden): For miden, set storage is "exec.account::set_item" and it expects the value to be + // on the stack top + let slot_miden_expr = dest.clone().to_miden_expr(); + cfg.push_to_miden_stack(format!("STORAGE_SLOT_{}", slot_miden_expr)); + cfg.push_miden_instr("exec.account::set_item".to_string()); cfg.add( vartab, @@ -1456,6 +1461,12 @@ fn pre_incdec( value = soroban_encode_arg(value, cfg, vartab, ns) } + // Poc(miden): For miden, set storage is "exec.account::set_item" and it expects the value to be + // on the stack top + let slot_miden_expr = dest.clone().to_miden_expr(); + cfg.push_to_miden_stack(format!("STORAGE_SLOT_{}", slot_miden_expr)); + cfg.push_miden_instr("exec.account::set_item".to_string()); + cfg.add( vartab, Instr::SetStorage { @@ -2920,12 +2931,20 @@ fn add( right: &ast::Expression, opt: &Options, ) -> Expression { + let right = Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)); + let left = Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)); + + // POC(miden): Add expects the first argument to be on the stack top, and the second argument is provided as immediate + let miden_instr = format!("add.{}", right.clone().to_miden_expr()); + cfg.push_miden_instr(miden_instr); + //cfg.miden_instrs.push(miden_instr); + Expression::Add { loc: *loc, ty: ty.clone(), overflowing, - left: Box::new(expression(left, cfg, contract_no, func, ns, vartab, opt)), - right: Box::new(expression(right, cfg, contract_no, func, ns, vartab, opt)), + left, + right, } } @@ -3262,6 +3281,11 @@ pub fn assign_single( value = soroban_encode_arg(value, cfg, vartab, ns); } + // POC(miden): Push the storage slot to the Miden stack before the set_item call + let slot_miden_expr = dest.clone().to_miden_expr(); + cfg.push_to_miden_stack(format!("STORAGE_SLOT_{}", slot_miden_expr)); + cfg.push_miden_instr("exec.account::set_item".to_string()); + cfg.add( vartab, Instr::SetStorage { @@ -3797,6 +3821,7 @@ fn array_subscript( ty: array_ty.clone(), exprs: vec![array, index], }, + Target::Miden => unimplemented!(), }; } @@ -4192,6 +4217,15 @@ pub fn load_storage( ) -> Expression { let res = vartab.temp_anonymous(ty); + //POC(Miden): storage load in miden is "exec.account::get_item", and expects the key to be on the stack + let storage_slot_miden_expr = format!("STORAGE_SLOT_{}", storage.clone().to_miden_expr()); + + // push the storage slot expression onto the stack + cfg.push_to_miden_stack(storage_slot_miden_expr); + + // add the storage load instruction + cfg.push_miden_instr("exec.account::get_item".to_string()); + cfg.add( vartab, Instr::LoadStorage { diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 6d8dac330..d8c23a495 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -950,6 +950,18 @@ impl RetrieveType for Expression { } impl Expression { + /// POC(miden): Convert expression to miden expression string + /// This is a very naive implementation and only handles a few cases. + pub fn to_miden_expr(self) -> String { + match self { + Expression::NumberLiteral { value, .. } => value.to_string(), + _ => { + // For unsupported expressions, return a placeholder + "UNSUPPORTED_EXPR".to_string() + } + } + } + /// Increment an expression by some value. pub(crate) fn add_u32(self, other: Expression) -> Self { Expression::Add { diff --git a/src/codegen/statements/mod.rs b/src/codegen/statements/mod.rs index cd3a67ada..98bbd4074 100644 --- a/src/codegen/statements/mod.rs +++ b/src/codegen/statements/mod.rs @@ -851,6 +851,9 @@ fn returns( .map(|(left, right)| try_load_and_cast(&right.loc(), &right, &left.ty, ns, cfg, vartab)) .collect(); + //POC(Miden): for miden, the return instr returns the data on the stack + cfg.push_miden_instr("exec.sys::truncate_stack".to_string()); + cfg.add(vartab, Instr::Return { value: cast_values }); } diff --git a/src/emit/binary.rs b/src/emit/binary.rs index 420fd7762..b636e22e0 100644 --- a/src/emit/binary.rs +++ b/src/emit/binary.rs @@ -41,6 +41,7 @@ use inkwell::OptimizationLevel; use once_cell::sync::OnceCell; use solang_parser::pt; +use super::miden; #[cfg(feature = "soroban")] use super::soroban; @@ -170,6 +171,8 @@ pub struct Binary<'a> { global_constant_strings: RefCell, PointerValue<'a>>>, pub return_data: RefCell>>, + // POC(Miden): store the generated instructions as strings + pub miden_instrs: Option>>, } impl<'a> Binary<'a> { @@ -191,6 +194,11 @@ impl<'a> Binary<'a> { Target::Soroban => { soroban::SorobanTarget::build(context, &std_lib, contract, ns, opt, _contract_no) } + + Target::Miden => { + miden::Midentarget::build(context, &std_lib, contract, ns, opt, _contract_no) + } + _ => unimplemented!("target not implemented"), } } @@ -200,6 +208,17 @@ impl<'a> Binary<'a> { /// each time a bin of this type is created). /// Pass our module to llvm for optimization and compilation pub fn code(&self, generate: Generate) -> Result, String> { + if self.ns.target == Target::Miden { + return Ok(self + .miden_instrs + .as_ref() + .unwrap() + .borrow() + .join("\n") + .as_bytes() + .to_vec()); + } + // return cached result if available if !self.code.borrow().is_empty() { return Ok(self.code.borrow().clone()); @@ -442,6 +461,11 @@ impl<'a> Binary<'a> { vector_init_empty: context.ptr_type(AddressSpace::default()).const_null(), global_constant_strings: RefCell::new(HashMap::new()), return_data: RefCell::new(None), + miden_instrs: if ns.target == Target::Miden { + Some(RefCell::new(Vec::new())) + } else { + None + }, } } diff --git a/src/emit/miden/mod.rs b/src/emit/miden/mod.rs new file mode 100644 index 000000000..80b237345 --- /dev/null +++ b/src/emit/miden/mod.rs @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: Apache-2.0 + +use crate::codegen::cfg::Instr; +use crate::codegen::Expression; +use crate::codegen::{cfg::ControlFlowGraph, Options}; + +use crate::{emit::Binary, sema::ast}; +use inkwell::{context::Context, module::Module}; +pub(super) mod target; + +pub struct Midentarget; + +impl Midentarget { + pub fn build<'a>( + context: &'a Context, + std_lib: &Module<'a>, + contract: &'a ast::Contract, + ns: &'a ast::Namespace, + opt: &'a Options, + _contract_no: usize, + ) -> Binary<'a> { + let filename = ns.files[contract.loc.file_no()].file_name(); + let mut bin = Binary::new( + context, + ns, + &contract.id.name, + &filename, + opt, + std_lib, + None, + ); + + // for each cfg, wrap its instructions in a function and copy it to the binary + for cfg in &contract.cfg { + if cfg.name == "storage_initializer" { + Self::emit_storage_initializer(cfg, &mut bin); + continue; + } + + if cfg.name.contains("constructor") { + continue; + } + + let name = cfg.name.split("::").last().unwrap(); + bin.miden_instrs + .as_ref() + .unwrap() + .borrow_mut() + .push(format!("export.{}", name)); + + for miden_instr in cfg.miden_instrs.iter() { + bin.miden_instrs + .as_ref() + .unwrap() + .borrow_mut() + .push(miden_instr.to_string()); + } + bin.miden_instrs + .as_ref() + .unwrap() + .borrow_mut() + .push("end".to_string()); + } + + bin + } + + pub fn emit_storage_initializer(cfg: &ControlFlowGraph, bin: &mut Binary) { + let use_miden_account = "use.miden::account"; + let use_miden_sys = "use.std::sys"; + + bin.miden_instrs + .as_ref() + .unwrap() + .borrow_mut() + .insert(0, use_miden_account.to_string()); + bin.miden_instrs + .as_ref() + .unwrap() + .borrow_mut() + .insert(1, use_miden_sys.to_string()); + + for instr in cfg.blocks[0].instr.iter().enumerate() { + if let Instr::SetStorage { + ty: _ty, + value: _value, + storage, + storage_type: _storage_type, + } = instr.1 + { + if let Expression::NumberLiteral { + loc: _loc, + ty: _ty, + value, + } = storage + { + println!("Set storage at slot: {}", value); + + let miden_instr = format!("const.STORAGE_SLOT_{}={}", value, value); + bin.miden_instrs + .as_ref() + .unwrap() + .borrow_mut() + .insert(instr.0 + 2, miden_instr); + } + } + } + } +} diff --git a/src/emit/miden/target.rs b/src/emit/miden/target.rs new file mode 100644 index 000000000..d2189f618 --- /dev/null +++ b/src/emit/miden/target.rs @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: Apache-2.0 + +use crate::codegen::cfg::HashTy; + +use crate::codegen::Expression; +use crate::emit::binary::Binary; +use crate::emit::miden::Midentarget; + +use crate::emit::ContractArgs; +use crate::emit::{TargetRuntime, Variable}; + +use crate::sema::ast; +use crate::sema::ast::CallTy; +use crate::sema::ast::{Function, Type}; + +use inkwell::types::{BasicTypeEnum, IntType}; +use inkwell::values::{ + ArrayValue, BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, IntValue, + PointerValue, +}; + +use solang_parser::pt::{Loc, StorageType}; +use std::collections::HashMap; + +// TODO: Implement TargetRuntime for SorobanTarget. +#[allow(unused_variables)] +impl<'a> TargetRuntime<'a> for Midentarget { + fn get_storage_int( + &self, + bin: &Binary<'a>, + function: FunctionValue, + slot: PointerValue<'a>, + ty: IntType<'a>, + ) -> IntValue<'a> { + todo!() + } + + fn storage_load( + &self, + bin: &Binary<'a>, + ty: &ast::Type, + slot: &mut IntValue<'a>, + function: FunctionValue<'a>, + storage_type: &Option, + ) -> BasicValueEnum<'a> { + //unimplemented!() + + bin.context + .i32_type() + .const_int(0, false) + .as_basic_value_enum() + } + + /// Recursively store a type to storage + fn storage_store( + &self, + bin: &Binary<'a>, + ty: &ast::Type, + existing: bool, + slot: &mut IntValue<'a>, + dest: BasicValueEnum<'a>, + function: FunctionValue<'a>, + storage_type: &Option, + ) { + + //unimplemented!() + + //bin.context.i32_type().const_int(0, false).as_basic_value_enum() + } + + /// Recursively clear storage. The default implementation is for slot-based storage + fn storage_delete( + &self, + bin: &Binary<'a>, + ty: &Type, + slot: &mut IntValue<'a>, + function: FunctionValue<'a>, + ) { + unimplemented!() + } + + // Bytes and string have special storage layout + fn set_storage_string( + &self, + bin: &Binary<'a>, + function: FunctionValue<'a>, + slot: PointerValue<'a>, + dest: BasicValueEnum<'a>, + ) { + unimplemented!() + } + + fn get_storage_string( + &self, + bin: &Binary<'a>, + function: FunctionValue, + slot: PointerValue<'a>, + ) -> PointerValue<'a> { + unimplemented!() + } + + fn set_storage_extfunc( + &self, + bin: &Binary<'a>, + function: FunctionValue, + slot: PointerValue, + dest: PointerValue, + dest_ty: BasicTypeEnum, + ) { + unimplemented!() + } + + fn get_storage_extfunc( + &self, + bin: &Binary<'a>, + function: FunctionValue, + slot: PointerValue<'a>, + ) -> PointerValue<'a> { + unimplemented!() + } + + fn get_storage_bytes_subscript( + &self, + bin: &Binary<'a>, + function: FunctionValue, + slot: IntValue<'a>, + index: IntValue<'a>, + loc: Loc, + ) -> IntValue<'a> { + unimplemented!() + } + + fn set_storage_bytes_subscript( + &self, + bin: &Binary<'a>, + function: FunctionValue, + slot: IntValue<'a>, + index: IntValue<'a>, + value: IntValue<'a>, + loc: Loc, + ) { + unimplemented!() + } + + fn storage_subscript( + &self, + bin: &Binary<'a>, + function: FunctionValue<'a>, + ty: &Type, + slot: IntValue<'a>, + index: BasicValueEnum<'a>, + ) -> IntValue<'a> { + unimplemented!() + } + + fn storage_push( + &self, + bin: &Binary<'a>, + function: FunctionValue<'a>, + ty: &Type, + slot: IntValue<'a>, + val: Option>, + ) -> BasicValueEnum<'a> { + unimplemented!() + } + + fn storage_pop( + &self, + bin: &Binary<'a>, + function: FunctionValue<'a>, + ty: &Type, + slot: IntValue<'a>, + load: bool, + loc: Loc, + ) -> Option> { + unimplemented!() + } + + fn storage_array_length( + &self, + _bin: &Binary<'a>, + _function: FunctionValue, + _slot: IntValue<'a>, + _elem_ty: &Type, + ) -> IntValue<'a> { + unimplemented!() + } + + /// keccak256 hash + fn keccak256_hash( + &self, + bin: &Binary<'a>, + src: PointerValue, + length: IntValue, + dest: PointerValue, + ) { + unimplemented!() + } + + /// Prints a string + /// TODO: Implement this function, with a call to the `log` function in the Soroban runtime. + fn print(&self, bin: &Binary, string: PointerValue, length: IntValue) { + unimplemented!() + } + + /// Return success without any result + fn return_empty_abi(&self, bin: &Binary) { + unimplemented!() + } + + /// Return failure code + fn return_code<'b>(&self, bin: &'b Binary, ret: IntValue<'b>) { + unimplemented!() + } + + /// Return failure without any result + fn assert_failure(&self, bin: &Binary, data: PointerValue, length: IntValue) { + bin.builder.build_unreachable().unwrap(); + } + + fn builtin_function( + &self, + bin: &Binary<'a>, + function: FunctionValue<'a>, + builtin_func: &Function, + args: &[BasicMetadataValueEnum<'a>], + first_arg_type: Option, + ) -> Option> { + unimplemented!() + } + + /// Calls constructor + fn create_contract<'b>( + &mut self, + bin: &Binary<'b>, + function: FunctionValue<'b>, + success: Option<&mut BasicValueEnum<'b>>, + contract_no: usize, + address: PointerValue<'b>, + encoded_args: BasicValueEnum<'b>, + encoded_args_len: BasicValueEnum<'b>, + contract_args: ContractArgs<'b>, + loc: Loc, + ) { + unimplemented!() + } + + /// call external function + fn external_call<'b>( + &self, + bin: &Binary<'b>, + function: FunctionValue<'b>, + success: Option<&mut BasicValueEnum<'b>>, + payload: PointerValue<'b>, + payload_len: IntValue<'b>, + address: Option>, + contract_args: ContractArgs<'b>, + ty: CallTy, + loc: Loc, + ) { + unimplemented!() + } + + /// send value to address + fn value_transfer<'b>( + &self, + _bin: &Binary<'b>, + _function: FunctionValue, + _success: Option<&mut BasicValueEnum<'b>>, + _address: PointerValue<'b>, + _value: IntValue<'b>, + loc: Loc, + ) { + unimplemented!() + } + + /// builtin expressions + fn builtin<'b>( + &self, + bin: &Binary<'b>, + expr: &Expression, + vartab: &HashMap>, + function: FunctionValue<'b>, + ) -> BasicValueEnum<'b> { + unimplemented!() + } + + /// Return the return data from an external call (either revert error or return values) + fn return_data<'b>(&self, bin: &Binary<'b>, function: FunctionValue<'b>) -> PointerValue<'b> { + bin.return_data.borrow().unwrap() + } + + /// Return the value we received + fn value_transferred<'b>(&self, bin: &Binary<'b>) -> IntValue<'b> { + unimplemented!() + } + + /// Terminate execution, destroy bin and send remaining funds to addr + fn selfdestruct<'b>(&self, bin: &Binary<'b>, addr: ArrayValue<'b>) { + unimplemented!() + } + + /// Crypto Hash + fn hash<'b>( + &self, + bin: &Binary<'b>, + function: FunctionValue<'b>, + hash: HashTy, + string: PointerValue<'b>, + length: IntValue<'b>, + ) -> IntValue<'b> { + unimplemented!() + } + + /// Emit event + fn emit_event<'b>( + &self, + bin: &Binary<'b>, + function: FunctionValue<'b>, + data: BasicValueEnum<'b>, + topics: &[BasicValueEnum<'b>], + ) { + unimplemented!() + } + + /// Return ABI encoded data + fn return_abi_data<'b>( + &self, + bin: &Binary<'b>, + data: PointerValue<'b>, + data_len: BasicValueEnum<'b>, + ) { + unimplemented!() + } +} diff --git a/src/emit/mod.rs b/src/emit/mod.rs index 18b237943..b70fd6315 100644 --- a/src/emit/mod.rs +++ b/src/emit/mod.rs @@ -26,6 +26,8 @@ pub mod solana; #[cfg(feature = "soroban")] pub mod soroban; + +pub mod miden; mod storage; mod strings; diff --git a/src/lib.rs b/src/lib.rs index 5ab101d45..ecb690175 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,7 @@ pub enum Target { /// Ethereum EVM, see EVM, Soroban, + Miden, } impl fmt::Display for Target { @@ -42,6 +43,7 @@ impl fmt::Display for Target { Target::Polkadot { .. } => write!(f, "Polkadot"), Target::EVM => write!(f, "EVM"), Target::Soroban => write!(f, "Soroban"), + Target::Miden => write!(f, "Miden"), } } } @@ -55,6 +57,7 @@ impl PartialEq for Target { Target::Polkadot { .. } => matches!(other, Target::Polkadot { .. }), Target::EVM => matches!(other, Target::EVM), Target::Soroban => matches!(other, Target::Soroban), + Target::Miden => matches!(other, Target::Miden), } } } @@ -88,6 +91,8 @@ impl Target { match self { // Solana uses ELF dynamic shared object (BPF) Target::Solana => "so", + // For Miden, file extension is .masm + Target::Miden => "masm", // Everything else generates webassembly _ => "wasm", } diff --git a/src/linker/mod.rs b/src/linker/mod.rs index 30ecb10d7..933d75fdb 100644 --- a/src/linker/mod.rs +++ b/src/linker/mod.rs @@ -23,6 +23,7 @@ pub fn link(input: &[u8], name: &str, target: Target) -> Vec { address_length: _, value_length: _, } => polkadot_wasm::link(input, name), + Target::Miden => input.to_vec(), _ => panic!("linker not implemented for target {target:?}"), } } diff --git a/src/sema/namespace.rs b/src/sema/namespace.rs index 8915935b9..accdf5d21 100644 --- a/src/sema/namespace.rs +++ b/src/sema/namespace.rs @@ -42,6 +42,7 @@ impl Namespace { } => (address_length, value_length), Target::Solana => (32, 8), Target::Soroban => (32, 64), + Target::Miden => (32, 64), }; let mut ns = Namespace { diff --git a/src/sema/yul/builtin.rs b/src/sema/yul/builtin.rs index 48a913830..3a6454b1a 100644 --- a/src/sema/yul/builtin.rs +++ b/src/sema/yul/builtin.rs @@ -22,6 +22,7 @@ impl YulBuiltinPrototype { Target::EVM => self.availability[0], Target::Polkadot { .. } => self.availability[1], Target::Solana => self.availability[2], + Target::Miden => unimplemented!(), Target::Soroban => unimplemented!(), } } diff --git a/tests/contract.rs b/tests/contract.rs index 65c2ccb65..4223c4e8c 100644 --- a/tests/contract.rs +++ b/tests/contract.rs @@ -102,7 +102,7 @@ fn parse_file(path: PathBuf, target: Target) -> io::Result<()> { contract.emit(&ns, &Default::default(), contract_no) } Target::EVM => b"beep".to_vec(), - Target::Soroban => { + Target::Soroban | Target::Miden => { todo!() } };