diff --git a/Cargo.lock b/Cargo.lock index 92cbf4640e1..be6c4f15d99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6901,7 +6901,6 @@ name = "test" version = "0.0.0" dependencies = [ "anyhow", - "assert_matches", "bytes", "clap 4.5.1", "colored", diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index 4c323351209..6ae375d4015 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -1594,12 +1594,18 @@ pub fn dependency_namespace( node: NodeIx, engines: &Engines, contract_id_value: Option, + experimental: sway_core::ExperimentalFlags, ) -> Result> { // TODO: Clean this up when config-time constants v1 are removed. let node_idx = &graph[node]; let name = Some(Ident::new_no_span(node_idx.name.clone())); let mut namespace = if let Some(contract_id_value) = contract_id_value { - namespace::Module::default_with_contract_id(engines, name.clone(), contract_id_value)? + namespace::Module::default_with_contract_id( + engines, + name.clone(), + contract_id_value, + experimental, + )? } else { namespace::Module::default() }; @@ -1633,6 +1639,7 @@ pub fn dependency_namespace( engines, name.clone(), contract_id_value, + experimental, )?; ns.is_external = true; ns.name = name; @@ -2087,7 +2094,9 @@ fn build_profile_from_opts( profile.include_tests |= tests; profile.json_abi_with_callpaths |= pkg.json_abi_with_callpaths; profile.error_on_warnings |= error_on_warnings; - profile.experimental = experimental.clone(); + profile.experimental = ExperimentalFlags { + new_encoding: experimental.new_encoding, + }; Ok(profile) } @@ -2119,6 +2128,7 @@ pub fn build_with_options(build_options: BuildOpts) -> Result { pkg, build_target, member_filter, + experimental, .. } = &build_options; @@ -2158,7 +2168,15 @@ pub fn build_with_options(build_options: BuildOpts) -> Result { // Build it! let mut built_workspace = Vec::new(); let build_start = std::time::Instant::now(); - let built_packages = build(&build_plan, *build_target, &build_profile, &outputs)?; + let built_packages = build( + &build_plan, + *build_target, + &build_profile, + &outputs, + sway_core::ExperimentalFlags { + new_encoding: experimental.new_encoding, + }, + )?; let output_dir = pkg.output_directory.as_ref().map(PathBuf::from); let finished = ansi_term::Colour::Green.bold().paint("Finished"); @@ -2261,6 +2279,7 @@ pub fn build( target: BuildTarget, profile: &BuildProfile, outputs: &HashSet, + experimental: sway_core::ExperimentalFlags, ) -> anyhow::Result> { let mut built_packages = Vec::new(); @@ -2339,6 +2358,7 @@ pub fn build( node, &engines, None, + experimental, ) { Ok(o) => o, Err(errs) => return fail(&[], &errs), @@ -2402,6 +2422,7 @@ pub fn build( node, &engines, contract_id_value.clone(), + experimental, ) { Ok(o) => o, Err(errs) => { @@ -2595,6 +2616,7 @@ fn update_json_type_declaration( /// Compile the entire forc package and return the lexed, parsed and typed programs /// of the dependencies and project. /// The final item in the returned vector is the project. +#[allow(clippy::too_many_arguments)] pub fn check( plan: &BuildPlan, build_target: BuildTarget, @@ -2603,6 +2625,7 @@ pub fn check( include_tests: bool, engines: &Engines, retrigger_compilation: Option>, + experimental: sway_core::ExperimentalFlags, ) -> anyhow::Result, Handler)>> { let mut lib_namespace_map = Default::default(); let mut source_map = SourceMap::new(); @@ -2633,6 +2656,7 @@ pub fn check( node, engines, contract_id_value, + experimental, ) .expect("failed to create dependency namespace"); diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_launch.rs b/forc-plugins/forc-debug/src/server/handlers/handle_launch.rs index 3f6ce36484e..ac007653179 100644 --- a/forc-plugins/forc-debug/src/server/handlers/handle_launch.rs +++ b/forc-plugins/forc-debug/src/server/handlers/handle_launch.rs @@ -53,6 +53,10 @@ impl DapServer { } } + let experimental = sway_core::ExperimentalFlags { + new_encoding: false, + }; + // 1. Build the packages let manifest_file = forc_pkg::manifest::ManifestFile::from_dir(&self.state.program_path) .map_err(|err| AdapterError::BuildFailed { @@ -105,6 +109,7 @@ impl DapServer { ..Default::default() }, &outputs, + experimental, ) .map_err(|err| AdapterError::BuildFailed { reason: format!("build packages: {:?}", err), diff --git a/forc-plugins/forc-doc/src/cli.rs b/forc-plugins/forc-doc/src/cli.rs index 0817f25c9ff..1dae015f022 100644 --- a/forc-plugins/forc-doc/src/cli.rs +++ b/forc-plugins/forc-doc/src/cli.rs @@ -54,4 +54,7 @@ pub struct Command { #[cfg(test)] pub(crate) doc_path: Option, + + #[clap(long)] + pub experimental_new_encoding: bool, } diff --git a/forc-plugins/forc-doc/src/main.rs b/forc-plugins/forc-doc/src/main.rs index b9d3c79fba2..affa713394a 100644 --- a/forc-plugins/forc-doc/src/main.rs +++ b/forc-plugins/forc-doc/src/main.rs @@ -53,7 +53,13 @@ struct ProgramInfo<'a> { pub fn main() -> Result<()> { let build_instructions = Command::parse(); - let (doc_path, pkg_manifest) = compile_html(&build_instructions, &get_doc_dir)?; + let (doc_path, pkg_manifest) = compile_html( + &build_instructions, + &get_doc_dir, + sway_core::ExperimentalFlags { + new_encoding: build_instructions.experimental_new_encoding, + }, + )?; // CSS, icons and logos static ASSETS_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/src/static.files"); @@ -169,6 +175,7 @@ fn write_content(rendered_docs: RenderedDocumentation, doc_path: &Path) -> Resul pub fn compile_html( build_instructions: &Command, get_doc_dir: &dyn Fn(&Command) -> String, + experimental: sway_core::ExperimentalFlags, ) -> Result<(PathBuf, Box)> { // get manifest directory let dir = if let Some(ref path) = build_instructions.manifest_path { @@ -221,6 +228,7 @@ pub fn compile_html( tests_enabled, &engines, None, + experimental, )?; let raw_docs = if !build_instructions.no_deps { diff --git a/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs b/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs index 1080b1aed07..af6c26f70a0 100644 --- a/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs +++ b/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs @@ -10,6 +10,7 @@ use std::{ collections::HashSet, path::{Path, PathBuf}, }; +use sway_core::ExperimentalFlags; /// The path to the generated HTML of the type the traits are implemented on. const IMPL_FOR: &str = "bar/struct.Bar.html"; @@ -25,7 +26,14 @@ fn test_impl_traits_default() { doc_path: Some(doc_dir_name.into()), ..Default::default() }; - let (doc_path, _) = compile_html(&command, &get_doc_dir).unwrap(); + let (doc_path, _) = compile_html( + &command, + &get_doc_dir, + ExperimentalFlags { + new_encoding: false, + }, + ) + .unwrap(); assert_index_html( &doc_path, project_name, @@ -37,7 +45,7 @@ fn test_impl_traits_default() { assert_search_js( &doc_path, &expect![[r#" - var SEARCH_INDEX={"core":[{"html_filename":"trait.AsRawSlice.html","module_info":["core","raw_slice"],"name":"AsRawSlice","preview":"Trait to return a type as a raw_slice.\n","type_name":"trait"},{"html_filename":"fn.from_str_array.html","module_info":["core","str"],"name":"from_str_array","preview":"","type_name":"function"},{"html_filename":"trait.Add.html","module_info":["core","ops"],"name":"Add","preview":"Trait for the addition of two values.\n","type_name":"trait"},{"html_filename":"trait.Subtract.html","module_info":["core","ops"],"name":"Subtract","preview":"Trait for the subtraction of two values.\n","type_name":"trait"},{"html_filename":"trait.Multiply.html","module_info":["core","ops"],"name":"Multiply","preview":"Trait for the multiplication of two values.\n","type_name":"trait"},{"html_filename":"trait.Divide.html","module_info":["core","ops"],"name":"Divide","preview":"Trait for the division of two values.\n","type_name":"trait"},{"html_filename":"trait.Mod.html","module_info":["core","ops"],"name":"Mod","preview":"Trait for the modulo of two values.\n","type_name":"trait"},{"html_filename":"trait.Not.html","module_info":["core","ops"],"name":"Not","preview":"Trait to invert a type.\n","type_name":"trait"},{"html_filename":"trait.Eq.html","module_info":["core","ops"],"name":"Eq","preview":"Trait to evaluate if two types are equal.\n","type_name":"trait"},{"html_filename":"trait.Ord.html","module_info":["core","ops"],"name":"Ord","preview":"Trait to evaluate if one value is greater or less than another of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseAnd.html","module_info":["core","ops"],"name":"BitwiseAnd","preview":"Trait to bitwise AND two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseOr.html","module_info":["core","ops"],"name":"BitwiseOr","preview":"Trait to bitwise OR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseXor.html","module_info":["core","ops"],"name":"BitwiseXor","preview":"Trait to bitwise XOR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.Shift.html","module_info":["core","ops"],"name":"Shift","preview":"Trait to bit shift a value.\n","type_name":"trait"},{"html_filename":"struct.StorageKey.html","module_info":["core","storage"],"name":"StorageKey","preview":"Describes a location in storage.\n","type_name":"struct"},{"html_filename":"struct.Buffer.html","module_info":["core","codec"],"name":"Buffer","preview":"","type_name":"struct"},{"html_filename":"trait.AbiEncode.html","module_info":["core","codec"],"name":"AbiEncode","preview":"","type_name":"trait"},{"html_filename":"fn.encode.html","module_info":["core","codec"],"name":"encode","preview":"","type_name":"function"}],"impl_traits":[{"html_filename":"trait.Foo.html","module_info":["impl_traits","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits","bar"],"name":"Bar","preview":"","type_name":"struct"}]}; + var SEARCH_INDEX={"core":[{"html_filename":"trait.AsRawSlice.html","module_info":["core","raw_slice"],"name":"AsRawSlice","preview":"Trait to return a type as a raw_slice.\n","type_name":"trait"},{"html_filename":"fn.from_str_array.html","module_info":["core","str"],"name":"from_str_array","preview":"","type_name":"function"},{"html_filename":"trait.Add.html","module_info":["core","ops"],"name":"Add","preview":"Trait for the addition of two values.\n","type_name":"trait"},{"html_filename":"trait.Subtract.html","module_info":["core","ops"],"name":"Subtract","preview":"Trait for the subtraction of two values.\n","type_name":"trait"},{"html_filename":"trait.Multiply.html","module_info":["core","ops"],"name":"Multiply","preview":"Trait for the multiplication of two values.\n","type_name":"trait"},{"html_filename":"trait.Divide.html","module_info":["core","ops"],"name":"Divide","preview":"Trait for the division of two values.\n","type_name":"trait"},{"html_filename":"trait.Mod.html","module_info":["core","ops"],"name":"Mod","preview":"Trait for the modulo of two values.\n","type_name":"trait"},{"html_filename":"trait.Not.html","module_info":["core","ops"],"name":"Not","preview":"Trait to invert a type.\n","type_name":"trait"},{"html_filename":"trait.Eq.html","module_info":["core","ops"],"name":"Eq","preview":"Trait to evaluate if two types are equal.\n","type_name":"trait"},{"html_filename":"trait.Ord.html","module_info":["core","ops"],"name":"Ord","preview":"Trait to evaluate if one value is greater or less than another of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseAnd.html","module_info":["core","ops"],"name":"BitwiseAnd","preview":"Trait to bitwise AND two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseOr.html","module_info":["core","ops"],"name":"BitwiseOr","preview":"Trait to bitwise OR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseXor.html","module_info":["core","ops"],"name":"BitwiseXor","preview":"Trait to bitwise XOR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.Shift.html","module_info":["core","ops"],"name":"Shift","preview":"Trait to bit shift a value.\n","type_name":"trait"},{"html_filename":"fn.ok_str_eq.html","module_info":["core","ops"],"name":"ok_str_eq","preview":"","type_name":"function"},{"html_filename":"struct.StorageKey.html","module_info":["core","storage"],"name":"StorageKey","preview":"Describes a location in storage.\n","type_name":"struct"},{"html_filename":"struct.Buffer.html","module_info":["core","codec"],"name":"Buffer","preview":"","type_name":"struct"},{"html_filename":"struct.BufferReader.html","module_info":["core","codec"],"name":"BufferReader","preview":"","type_name":"struct"},{"html_filename":"trait.AbiDecode.html","module_info":["core","codec"],"name":"AbiDecode","preview":"","type_name":"trait"},{"html_filename":"trait.AbiEncode.html","module_info":["core","codec"],"name":"AbiEncode","preview":"","type_name":"trait"},{"html_filename":"fn.encode.html","module_info":["core","codec"],"name":"encode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode.html","module_info":["core","codec"],"name":"abi_decode","preview":"","type_name":"function"},{"html_filename":"fn.contract_call.html","module_info":["core","codec"],"name":"contract_call","preview":"","type_name":"function"},{"html_filename":"fn.decode_script_data.html","module_info":["core","codec"],"name":"decode_script_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_first_param.html","module_info":["core","codec"],"name":"decode_first_param","preview":"","type_name":"function"},{"html_filename":"fn.decode_second_param.html","module_info":["core","codec"],"name":"decode_second_param","preview":"","type_name":"function"}],"impl_traits":[{"html_filename":"trait.Foo.html","module_info":["impl_traits","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits","bar"],"name":"Bar","preview":"","type_name":"struct"}]}; "object"==typeof exports&&"undefined"!=typeof module&&(module.exports=SEARCH_INDEX);"#]], ); assert_file_tree( @@ -45,11 +53,19 @@ fn test_impl_traits_default() { project_name, vec![ "core/all.html", + "core/codec/fn.abi_decode.html", + "core/codec/fn.contract_call.html", + "core/codec/fn.decode_first_param.html", + "core/codec/fn.decode_script_data.html", + "core/codec/fn.decode_second_param.html", "core/codec/fn.encode.html", "core/codec/index.html", "core/codec/struct.Buffer.html", + "core/codec/struct.BufferReader.html", + "core/codec/trait.AbiDecode.html", "core/codec/trait.AbiEncode.html", "core/index.html", + "core/ops/fn.ok_str_eq.html", "core/ops/index.html", "core/ops/trait.Add.html", "core/ops/trait.BitwiseAnd.html", @@ -91,7 +107,14 @@ fn test_impl_traits_no_deps() { no_deps: true, ..Default::default() }; - let (doc_path, _) = compile_html(&command, &get_doc_dir).unwrap(); + let (doc_path, _) = compile_html( + &command, + &get_doc_dir, + ExperimentalFlags { + new_encoding: false, + }, + ) + .unwrap(); assert_index_html( &doc_path, project_name, diff --git a/forc/src/cli/commands/check.rs b/forc/src/cli/commands/check.rs index 97627f2c5bc..c25e05a478e 100644 --- a/forc/src/cli/commands/check.rs +++ b/forc/src/cli/commands/check.rs @@ -44,6 +44,10 @@ pub struct Command { /// Possible values: PUBLIC, LOCAL, #[clap(long)] pub ipfs_node: Option, + + /// Set of experimental flags + #[clap(long)] + pub experimental_new_encoding: bool, } pub(crate) fn exec(command: Command) -> ForcResult<()> { diff --git a/forc/src/ops/forc_check.rs b/forc/src/ops/forc_check.rs index 457d8de7370..3236d16ab54 100644 --- a/forc/src/ops/forc_check.rs +++ b/forc/src/ops/forc_check.rs @@ -4,7 +4,7 @@ use forc_pkg as pkg; use forc_pkg::manifest::GenericManifestFile; use pkg::manifest::ManifestFile; use std::path::PathBuf; -use sway_core::{language::ty, Engines}; +use sway_core::{language::ty, Engines, ExperimentalFlags}; use sway_error::handler::Handler; pub fn check(command: CheckCommand, engines: &Engines) -> Result<(Option, Handler)> { @@ -16,6 +16,7 @@ pub fn check(command: CheckCommand, engines: &Engines) -> Result<(Option Result<(Option "smo", Intrinsic::Not => "not", Intrinsic::JmpMem => "jmp_mem", + Intrinsic::ContractCall => "contract_call", + Intrinsic::ContractRet => "contract_ret", }; write!(f, "{s}") } @@ -118,6 +122,8 @@ impl Intrinsic { "__smo" => Smo, "__not" => Not, "__jmp_mem" => JmpMem, + "__contract_call" => ContractCall, + "__contract_ret" => ContractRet, _ => return None, }) } diff --git a/sway-core/src/abi_generation/evm_abi.rs b/sway-core/src/abi_generation/evm_abi.rs index 2692b482c51..117adab860f 100644 --- a/sway-core/src/abi_generation/evm_abi.rs +++ b/sway-core/src/abi_generation/evm_abi.rs @@ -15,10 +15,10 @@ pub fn generate_abi_program(program: &TyProgram, engines: &Engines) -> EvmAbiRes .iter() .map(|x| generate_abi_function(x, type_engine, decl_engine)) .collect(), - TyProgramKind::Script { main_function, .. } - | TyProgramKind::Predicate { main_function, .. } => { + TyProgramKind::Script { entry_function, .. } + | TyProgramKind::Predicate { entry_function, .. } => { vec![generate_abi_function( - main_function, + entry_function, type_engine, decl_engine, )] diff --git a/sway-core/src/abi_generation/fuel_abi.rs b/sway-core/src/abi_generation/fuel_abi.rs index e02187f49ca..d43066e7a75 100644 --- a/sway-core/src/abi_generation/fuel_abi.rs +++ b/sway-core/src/abi_generation/fuel_abi.rs @@ -44,8 +44,14 @@ pub fn generate_program_abi( configurables: Some(configurables), } } - TyProgramKind::Script { main_function, .. } - | TyProgramKind::Predicate { main_function, .. } => { + TyProgramKind::Script { + entry_function: main_function, + .. + } + | TyProgramKind::Predicate { + entry_function: main_function, + .. + } => { let main_function = decl_engine.get_function(main_function); let functions = vec![main_function.generate_abi_function(ctx, type_engine, decl_engine, types)]; diff --git a/sway-core/src/asm_generation/from_ir.rs b/sway-core/src/asm_generation/from_ir.rs index bf7ead4bd15..13cd48a7f67 100644 --- a/sway-core/src/asm_generation/from_ir.rs +++ b/sway-core/src/asm_generation/from_ir.rs @@ -11,10 +11,10 @@ use super::{ MidenVMAsmBuilder, }; -use crate::{BuildConfig, BuildTarget}; +use crate::{BuildConfig, BuildTarget, ExperimentalFlags}; use sway_error::handler::{ErrorEmitted, Handler}; -use sway_ir::*; +use sway_ir::{Context, Kind, Module}; pub fn compile_ir_to_asm( handler: &Handler, @@ -106,8 +106,16 @@ fn compile_module_to_asm( }) .collect(); - let abstract_program = - AbstractProgram::new(kind, data_section, entries, non_entries, reg_seqr); + let abstract_program = AbstractProgram::new( + kind, + data_section, + entries, + non_entries, + reg_seqr, + ExperimentalFlags { + new_encoding: context.experimental.new_encoding, + }, + ); if build_config .map(|cfg| cfg.print_intermediate_asm) diff --git a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs index 004f09ef271..3c18eb42f90 100644 --- a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs +++ b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs @@ -306,6 +306,7 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { arg3, } => self.compile_wide_modular_op(instr_val, op, result, arg1, arg2, arg3), FuelVmInstruction::JmpMem => self.compile_jmp_mem(instr_val), + FuelVmInstruction::Retd { ptr, len } => self.compile_retd(instr_val, ptr, len), }, InstOp::GetElemPtr { base, @@ -669,6 +670,24 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { Ok(()) } + fn compile_retd( + &mut self, + instr_val: &Value, + ptr: &Value, + len: &Value, + ) -> Result<(), CompileError> { + let ptr = self.value_to_register(ptr)?; + let len = self.value_to_register(len)?; + + self.cur_bytecode.push(Op { + opcode: Either::Left(VirtualOp::RETD(ptr, len)), + comment: String::new(), + owning_span: self.md_mgr.val_to_span(self.context, *instr_val), + }); + + Ok(()) + } + fn compile_wide_cmp_op( &mut self, instr_val: &Value, diff --git a/sway-core/src/asm_generation/programs.rs b/sway-core/src/asm_generation/programs.rs index 89f78ec91bf..85e64446550 100644 --- a/sway-core/src/asm_generation/programs.rs +++ b/sway-core/src/asm_generation/programs.rs @@ -11,6 +11,7 @@ use super::fuel::{ use crate::{ asm_lang::{allocated_ops::AllocatedOp, Label}, decl_engine::DeclRefFunction, + ExperimentalFlags, }; type SelectorOpt = Option<[u8; 4]>; @@ -36,6 +37,7 @@ pub(super) struct AbstractProgram { entries: Vec, non_entries: Vec, reg_seqr: RegisterSequencer, + experimental: ExperimentalFlags, } /// The entry point of an abstract program. diff --git a/sway-core/src/asm_generation/programs/abstract.rs b/sway-core/src/asm_generation/programs/abstract.rs index 0927935d9f3..8833e574caa 100644 --- a/sway-core/src/asm_generation/programs/abstract.rs +++ b/sway-core/src/asm_generation/programs/abstract.rs @@ -13,6 +13,7 @@ use crate::{ AllocatedAbstractOp, ConstantRegister, ControlFlowOp, VirtualImmediate12, VirtualImmediate18, }, + ExperimentalFlags, }; use sway_error::error::CompileError; @@ -26,6 +27,7 @@ impl AbstractProgram { entries: Vec, non_entries: Vec, reg_seqr: RegisterSequencer, + experimental: ExperimentalFlags, ) -> Self { AbstractProgram { kind, @@ -33,6 +35,7 @@ impl AbstractProgram { entries, non_entries, reg_seqr, + experimental, } } @@ -41,8 +44,14 @@ impl AbstractProgram { // function selector. let mut prologue = self.build_preamble(); - if self.kind == ProgramKind::Contract { - self.build_contract_abi_switch(&mut prologue); + match (self.experimental.new_encoding, self.kind) { + (true, ProgramKind::Contract) => { + self.build_jump_to_entry(&mut prologue); + } + (false, ProgramKind::Contract) => { + self.build_contract_abi_switch(&mut prologue); + } + _ => {} } // Keep track of the labels (and names) that represent program entry points. @@ -149,6 +158,16 @@ impl AbstractProgram { } } + // WHen the new encoding is used, jumps to the `__entry` function + fn build_jump_to_entry(&mut self, asm_buf: &mut AllocatedAbstractInstructionSet) { + let entry = self.entries.iter().find(|x| x.name == "__entry").unwrap(); + asm_buf.ops.push(AllocatedAbstractOp { + opcode: Either::Right(ControlFlowOp::Jump(entry.label)), + comment: "jump to abi method selector".into(), + owning_span: None, + }); + } + /// Builds the contract switch statement based on the first argument to a contract call: the /// 'selector'. /// See https://fuellabs.github.io/fuel-specs/master/vm#call-frames which diff --git a/sway-core/src/control_flow_analysis/dead_code_analysis.rs b/sway-core/src/control_flow_analysis/dead_code_analysis.rs index 7da1e368138..aa22d379cb5 100644 --- a/sway-core/src/control_flow_analysis/dead_code_analysis.rs +++ b/sway-core/src/control_flow_analysis/dead_code_analysis.rs @@ -284,13 +284,14 @@ impl<'cfg> ControlFlowGraph<'cfg> { // do a depth first traversal and cover individual inner ast nodes let decl_engine = engines.de(); let exit_node = Some(graph.add_node(("Program exit".to_string()).into())); + let mut entry_points = vec![]; let mut non_entry_points = vec![]; - for ast_entrypoint in module_nodes { - if ast_entrypoint.is_entry_point(decl_engine, tree_type) { - entry_points.push(ast_entrypoint); + for ast_node in module_nodes { + if ast_node.is_entry_point(decl_engine, tree_type) { + entry_points.push(ast_node); } else { - non_entry_points.push(ast_entrypoint); + non_entry_points.push(ast_node); } } for ast_entrypoint in non_entry_points.into_iter().chain(entry_points) { @@ -741,7 +742,7 @@ fn connect_trait_declaration( }, TraitNamespaceEntry { trait_idx: entry_node, - module_tree_type: tree_type.clone(), + module_tree_type: *tree_type, }, ); } @@ -765,7 +766,7 @@ fn connect_abi_declaration( }, TraitNamespaceEntry { trait_idx: entry_node, - module_tree_type: tree_type.clone(), + module_tree_type: *tree_type, }, ); @@ -1098,6 +1099,7 @@ fn connect_expression<'eng: 'cfg, 'cfg>( contract_call_params, selector, call_path_typeid, + contract_caller, .. } => { let fn_decl = decl_engine.get_function(fn_ref); @@ -1224,9 +1226,27 @@ fn connect_expression<'eng: 'cfg, 'cfg>( } } - // we evaluate every one of the function arguments let mut current_leaf = vec![fn_entrypoint]; + + // Connect contract call to contract caller + if let Some(contract_caller) = contract_caller { + let span = contract_caller.span.clone(); + connect_expression( + engines, + &contract_caller.expression, + graph, + ¤t_leaf, + exit_node, + "arg eval", + tree_type, + span, + options, + )?; + } + + // we evaluate every one of the function arguments for (_name, arg) in arguments { + let span = arg.span.clone(); current_leaf = connect_expression( engines, &arg.expression, @@ -1235,7 +1255,7 @@ fn connect_expression<'eng: 'cfg, 'cfg>( exit_node, "arg eval", tree_type, - arg.clone().span, + span, options, )?; } @@ -2111,7 +2131,7 @@ fn construct_dead_code_warning_from_node( .. } => return None, ty::TyAstNode { - content: ty::TyAstNodeContent::Declaration(..), + content: ty::TyAstNodeContent::Declaration(_), span, } => CompileWarning { span: span.clone(), diff --git a/sway-core/src/decl_engine/engine.rs b/sway-core/src/decl_engine/engine.rs index b2a819dd93e..c170d8a1664 100644 --- a/sway-core/src/decl_engine/engine.rs +++ b/sway-core/src/decl_engine/engine.rs @@ -7,7 +7,7 @@ use std::{ use sway_types::{ModuleId, Named, Spanned}; use crate::{ - concurrent_slab::{ConcurrentSlab, ListDisplay}, + concurrent_slab::ConcurrentSlab, decl_engine::*, engine_threading::*, language::ty::{ @@ -441,11 +441,11 @@ impl DeclEngine { /// [DisplayWithEngines]. pub fn pretty_print(&self, engines: &Engines) -> String { let mut builder = String::new(); - let mut list = vec![]; - for func in self.function_slab.values() { - list.push(format!("{:?}", engines.help_out(&*func))); + let mut list = String::with_capacity(1024 * 1024); + let funcs = self.function_slab.values(); + for (i, func) in funcs.iter().enumerate() { + list.push_str(&format!("{i} - {:?}\n", engines.help_out(func))); } - let list = ListDisplay { list }; write!(builder, "DeclEngine {{\n{list}\n}}").unwrap(); builder } diff --git a/sway-core/src/decl_engine/parsed_engine.rs b/sway-core/src/decl_engine/parsed_engine.rs index 816e4de914a..c3c15fc0709 100644 --- a/sway-core/src/decl_engine/parsed_engine.rs +++ b/sway-core/src/decl_engine/parsed_engine.rs @@ -327,4 +327,22 @@ impl ParsedDeclEngine { { self.get(index) } + + pub fn pretty_print(&self) -> String { + use std::fmt::Write; + let mut s = String::new(); + let _ = write!( + &mut s, + "Function Count: {}", + self.function_slab.values().len() + ); + for f in self.function_slab.values() { + let _ = write!(&mut s, "Function: {}", f.name); + for node in f.body.contents.iter() { + let _ = write!(&mut s, " Node: {:#?}", node); + } + } + + s + } } diff --git a/sway-core/src/engine_threading.rs b/sway-core/src/engine_threading.rs index ae975ff674d..bc5af70a052 100644 --- a/sway-core/src/engine_threading.rs +++ b/sway-core/src/engine_threading.rs @@ -178,6 +178,12 @@ impl DebugWithEngines for &T { } } +impl DebugWithEngines for std::sync::Arc { + fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { + (**self).fmt(f, engines) + } +} + impl DebugWithEngines for Option { fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { match self { diff --git a/sway-core/src/ir_generation.rs b/sway-core/src/ir_generation.rs index c56613a239a..c5b596deeb9 100644 --- a/sway-core/src/ir_generation.rs +++ b/sway-core/src/ir_generation.rs @@ -63,28 +63,32 @@ pub fn compile_program<'eng>( match kind { // predicates and scripts have the same codegen, their only difference is static // type-check time checks. - ty::TyProgramKind::Script { main_function } => compile::compile_script( + ty::TyProgramKind::Script { entry_function } => compile::compile_script( engines, &mut ctx, - main_function, + entry_function, root.namespace.module(), declarations, &logged_types, &messages_types, &test_fns, ), - ty::TyProgramKind::Predicate { main_function } => compile::compile_predicate( + ty::TyProgramKind::Predicate { entry_function } => compile::compile_predicate( engines, &mut ctx, - main_function, + entry_function, root.namespace.module(), declarations, &logged_types, &messages_types, &test_fns, ), - ty::TyProgramKind::Contract { abi_entries } => compile::compile_contract( + ty::TyProgramKind::Contract { + entry_function, + abi_entries, + } => compile::compile_contract( &mut ctx, + entry_function.as_ref(), abi_entries, root.namespace.module(), declarations, diff --git a/sway-core/src/ir_generation/compile.rs b/sway-core/src/ir_generation/compile.rs index 4c46b8d4095..66b8a8c2126 100644 --- a/sway-core/src/ir_generation/compile.rs +++ b/sway-core/src/ir_generation/compile.rs @@ -117,6 +117,7 @@ pub(super) fn compile_predicate( #[allow(clippy::too_many_arguments)] pub(super) fn compile_contract( context: &mut Context, + main_function: Option<&DeclId>, abi_entries: &[DeclId], namespace: &namespace::Module, declarations: &[ty::TyDecl], @@ -138,6 +139,20 @@ pub(super) fn compile_contract( declarations, ) .map_err(|err| vec![err])?; + + if let Some(main_function) = main_function { + compile_entry_function( + engines, + context, + &mut md_mgr, + module, + main_function, + logged_types_map, + messages_types_map, + None, + )?; + } + for decl in abi_entries { compile_abi_method( context, @@ -149,6 +164,7 @@ pub(super) fn compile_contract( engines, )?; } + compile_tests( engines, context, @@ -571,16 +587,14 @@ fn compile_abi_method( } }; - // An ABI method is always an entry point. - let is_entry = true; - compile_fn( engines, context, md_mgr, module, &ast_fn_decl, - is_entry, + // ABI are only entries when the "new encoding" is off + !context.experimental.new_encoding, Some(selector), logged_types_map, messages_types_map, diff --git a/sway-core/src/ir_generation/const_eval.rs b/sway-core/src/ir_generation/const_eval.rs index d0f08a8e8d0..35ef5cdbaaf 100644 --- a/sway-core/src/ir_generation/const_eval.rs +++ b/sway-core/src/ir_generation/const_eval.rs @@ -1153,6 +1153,11 @@ fn const_eval_intrinsic( } } } + Intrinsic::ContractCall | Intrinsic::ContractRet => { + Err(ConstEvalError::CannotBeEvaluatedToConst { + span: intrinsic.span.clone(), + }) + } } } diff --git a/sway-core/src/ir_generation/function.rs b/sway-core/src/ir_generation/function.rs index bd7249b6c63..a4e4dfa5cb5 100644 --- a/sway-core/src/ir_generation/function.rs +++ b/sway-core/src/ir_generation/function.rs @@ -440,6 +440,7 @@ impl<'eng> FnCompiler<'eng> { type_binding: _, call_path_typeid: _, deferred_monomorphization, + .. } => { if *deferred_monomorphization { return Err(CompileError::Internal("Trying to compile a deferred function application with deferred monomorphization", name.span())); @@ -1019,7 +1020,7 @@ impl<'eng> FnCompiler<'eng> { return Err(CompileError::Internal( "Unable to determine ID for log instance.", span, - )) + )); } Some(log_id) => { convert_literal_to_value(context, &Literal::U64(**log_id as u64)) @@ -1257,6 +1258,79 @@ impl<'eng> FnCompiler<'eng> { .unary_op(UnaryOpKind::Not, value); Ok(TerminatorValue::new(val, context)) } + Intrinsic::ContractCall => { + assert!(type_arguments.is_empty()); + + // Contract method arguments + let params = return_on_termination_or_extract!(self.compile_expression_to_value( + context, + md_mgr, + &arguments[0] + )?); + + // Coins + let coins = return_on_termination_or_extract!(self.compile_expression_to_value( + context, + md_mgr, + &arguments[1] + )?); + + // AssetId + let b256_ty = Type::get_b256(context); + let asset_id = return_on_termination_or_extract!( + self.compile_expression_to_value(context, md_mgr, &arguments[2])? + ); + let tmp_asset_id_name = self.lexical_map.insert_anon(); + let tmp_var = self + .function + .new_local_var(context, tmp_asset_id_name, b256_ty, None, false) + .map_err(|ir_error| { + CompileError::InternalOwned(ir_error.to_string(), Span::dummy()) + })?; + let tmp_val = self.current_block.append(context).get_local(tmp_var); + self.current_block.append(context).store(tmp_val, asset_id); + let asset_id = self.current_block.append(context).get_local(tmp_var); + + // Gas + let gas = return_on_termination_or_extract!(self.compile_expression_to_value( + context, + md_mgr, + &arguments[3] + )?); + + let span_md_idx = md_mgr.span_to_md(context, &span); + + let return_type = Type::get_unit(context); + let return_type = Type::new_ptr(context, return_type); + + let returned_value = self + .current_block + .append(context) + .contract_call(return_type, None, params, coins, asset_id, gas) + .add_metadatum(context, span_md_idx); + + Ok(TerminatorValue::new(returned_value, context)) + } + Intrinsic::ContractRet => { + let span_md_idx = md_mgr.span_to_md(context, &span); + + let ptr = return_on_termination_or_extract!(self.compile_expression_to_value( + context, + md_mgr, + &arguments[0] + )?); + let len = return_on_termination_or_extract!(self.compile_expression_to_value( + context, + md_mgr, + &arguments[1] + )?); + let r = self + .current_block + .append(context) + .retd(ptr, len) + .add_metadatum(context, span_md_idx); + Ok(TerminatorValue::new(r, context)) + } } } @@ -1702,7 +1776,7 @@ impl<'eng> FnCompiler<'eng> { .append(context) .contract_call( return_type, - ast_name.to_string(), + Some(ast_name.to_string()), ra_struct_ptr_val, coins, asset_id, @@ -1745,16 +1819,26 @@ impl<'eng> FnCompiler<'eng> { // cache, to uniquely identify a function instance, is the span and the type IDs of any // args and type parameters. It's using the Sway types rather than IR types, which would // be more accurate but also more fiddly. - let fn_key = ( - callee.span(), - callee - .parameters - .iter() - .map(|p| p.type_argument.type_id) - .collect(), - callee.type_parameters.iter().map(|tp| tp.type_id).collect(), - ); - let new_callee = match self.recreated_fns.get(&fn_key).copied() { + + let (fn_key, item) = if !callee.span().as_str().is_empty() { + let fn_key = ( + callee.span(), + callee + .parameters + .iter() + .map(|p| p.type_argument.type_id) + .collect(), + callee.type_parameters.iter().map(|tp| tp.type_id).collect(), + ); + ( + Some(fn_key.clone()), + self.recreated_fns.get(&fn_key).copied(), + ) + } else { + (None, None) + }; + + let new_callee = match item { Some(func) => func, None => { let callee_fn_decl = ty::TyFunctionDecl { @@ -1781,7 +1865,11 @@ impl<'eng> FnCompiler<'eng> { ) .map_err(|mut x| x.pop().unwrap())? .unwrap(); - self.recreated_fns.insert(fn_key, new_func); + + if let Some(fn_key) = fn_key { + self.recreated_fns.insert(fn_key, new_func); + } + new_func } }; diff --git a/sway-core/src/language/asm.rs b/sway-core/src/language/asm.rs index 530e4234ffd..c396c70fbb5 100644 --- a/sway-core/src/language/asm.rs +++ b/sway-core/src/language/asm.rs @@ -1,6 +1,6 @@ use std::hash::{Hash, Hasher}; -use sway_types::{Ident, Span}; +use sway_types::{BaseIdent, Ident, Span}; #[derive(Debug, Clone)] pub struct AsmOp { @@ -10,6 +10,17 @@ pub struct AsmOp { pub(crate) immediate: Option, } +impl AsmOp { + pub fn retd(ptr: BaseIdent, len: BaseIdent) -> Self { + AsmOp { + op_name: Ident::new_no_span("retd".to_string()), + op_args: vec![ptr, len], + span: Span::dummy(), + immediate: None, + } + } +} + impl Hash for AsmOp { fn hash(&self, state: &mut H) { self.op_name.hash(state); diff --git a/sway-core/src/language/parsed/declaration/function.rs b/sway-core/src/language/parsed/declaration/function.rs index 0ed8c39cbf4..c28ff4b633e 100644 --- a/sway-core/src/language/parsed/declaration/function.rs +++ b/sway-core/src/language/parsed/declaration/function.rs @@ -6,6 +6,13 @@ use crate::{ }; use sway_types::{ident::Ident, span::Span}; +#[derive(Debug, Clone)] +pub enum FunctionDeclarationKind { + Default, + Entry, + Test, +} + #[derive(Debug, Clone)] pub struct FunctionDeclaration { pub purity: Purity, @@ -18,6 +25,7 @@ pub struct FunctionDeclaration { pub return_type: TypeArgument, pub type_parameters: Vec, pub where_clause: Vec<(Ident, Vec)>, + pub kind: FunctionDeclarationKind, } #[derive(Debug, Clone)] diff --git a/sway-core/src/language/parsed/expression/match_branch.rs b/sway-core/src/language/parsed/expression/match_branch.rs index 6f497194e93..7cb1c3e1d7d 100644 --- a/sway-core/src/language/parsed/expression/match_branch.rs +++ b/sway-core/src/language/parsed/expression/match_branch.rs @@ -1,6 +1,5 @@ -use sway_types::span; - use super::{Expression, Scrutinee}; +use sway_types::span; #[derive(Debug, Clone)] pub struct MatchBranch { diff --git a/sway-core/src/language/parsed/mod.rs b/sway-core/src/language/parsed/mod.rs index e2d39843886..978339971d8 100644 --- a/sway-core/src/language/parsed/mod.rs +++ b/sway-core/src/language/parsed/mod.rs @@ -14,9 +14,8 @@ pub use include_statement::IncludeStatement; pub use module::{ParseModule, ParseSubmodule}; pub use program::{ParseProgram, TreeType}; use sway_error::handler::ErrorEmitted; -pub use use_statement::{ImportType, UseStatement}; - use sway_types::span::Span; +pub use use_statement::{ImportType, UseStatement}; use crate::Engines; diff --git a/sway-core/src/language/parsed/program.rs b/sway-core/src/language/parsed/program.rs index 4feeb2acbc1..29311c20705 100644 --- a/sway-core/src/language/parsed/program.rs +++ b/sway-core/src/language/parsed/program.rs @@ -16,7 +16,7 @@ pub struct ParseProgram { /// A Sway program can be either a contract, script, predicate, or a library. /// /// All submodules declared with `dep` should be `Library`s. -#[derive(Clone, Debug, PartialEq, Eq, EnumString)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, EnumString)] pub enum TreeType { #[strum(serialize = "predicate")] Predicate, diff --git a/sway-core/src/language/ty/ast_node.rs b/sway-core/src/language/ty/ast_node.rs index d7aec328abb..8d2b08fdb14 100644 --- a/sway-core/src/language/ty/ast_node.rs +++ b/sway-core/src/language/ty/ast_node.rs @@ -207,7 +207,7 @@ impl TyAstNode { .. } => { let decl = decl_engine.get_function(decl_id); - decl.is_entry() + decl.is_entry_or_test() } _ => false, } @@ -395,6 +395,23 @@ impl TyAstNode { Ok(()) }) } + + pub fn contract_fns(&self, engines: &Engines) -> Vec { + let mut fns = vec![]; + + if let TyAstNodeContent::Declaration(TyDecl::ImplTrait(decl)) = &self.content { + let decl = engines.de().get(&decl.decl_id); + if decl.is_impl_contract(engines.te()) { + for item in &decl.items { + if let TyTraitItem::Fn(f) = item { + fns.push(f.clone()); + } + } + } + } + + fns + } } #[derive(Clone, Debug)] diff --git a/sway-core/src/language/ty/declaration/declaration.rs b/sway-core/src/language/ty/declaration/declaration.rs index 7e41cb3c1ff..4566ad4af00 100644 --- a/sway-core/src/language/ty/declaration/declaration.rs +++ b/sway-core/src/language/ty/declaration/declaration.rs @@ -378,6 +378,18 @@ impl TyDecl { } } + pub fn get_trait_decl_ref(&self) -> Option { + if let TyDecl::TraitDecl(decl) = self { + Some(DeclRef::new( + decl.name.clone(), + decl.decl_id, + decl.decl_span.clone(), + )) + } else { + None + } + } + pub fn get_fun_decl_ref(&self) -> Option { if let TyDecl::FunctionDecl(FunctionDecl { name, diff --git a/sway-core/src/language/ty/declaration/function.rs b/sway-core/src/language/ty/declaration/function.rs index 20f7a2fb6ff..f1cd4eaafb0 100644 --- a/sway-core/src/language/ty/declaration/function.rs +++ b/sway-core/src/language/ty/declaration/function.rs @@ -7,7 +7,10 @@ use std::{ use sha2::{Digest, Sha256}; use sway_error::handler::{ErrorEmitted, Handler}; -use crate::{language::CallPath, semantic_analysis::type_check_context::MonomorphizeHelper}; +use crate::{ + language::{parsed::FunctionDeclarationKind, CallPath}, + semantic_analysis::type_check_context::MonomorphizeHelper, +}; use crate::{ decl_engine::*, @@ -24,6 +27,13 @@ use sway_types::{ Ident, Named, Span, Spanned, }; +#[derive(Clone, Debug)] +pub enum TyFunctionDeclKind { + Default, + Entry, + Test, +} + #[derive(Clone, Debug)] pub struct TyFunctionDecl { pub name: Ident, @@ -42,13 +52,14 @@ pub struct TyFunctionDecl { pub purity: Purity, pub where_clause: Vec<(Ident, Vec)>, pub is_trait_method_dummy: bool, + pub kind: TyFunctionDeclKind, } impl DebugWithEngines for TyFunctionDecl { fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { write!( f, - "{}{:?}{}({}):{}", + "{}{:?}{}({}):{}->{}", if self.is_trait_method_dummy { "dummy ".to_string() } else { @@ -60,7 +71,11 @@ impl DebugWithEngines for TyFunctionDecl { "<{}>", self.type_parameters .iter() - .map(|p| format!("{:?}", engines.help_out(p.initial_type_id))) + .map(|p| format!( + "{:?} -> {:?}", + engines.help_out(p.initial_type_id), + engines.help_out(p.type_id) + )) .collect::>() .join(", ") ) @@ -77,6 +92,7 @@ impl DebugWithEngines for TyFunctionDecl { .collect::>() .join(", "), engines.help_out(self.return_type.initial_type_id), + engines.help_out(self.return_type.type_id), ) } } @@ -163,6 +179,7 @@ impl HashWithEngines for TyFunctionDecl { implementing_for_typeid: _, where_clause: _, is_trait_method_dummy: _, + kind: _, } = self; name.hash(state); body.hash(state, engines); @@ -296,6 +313,7 @@ impl TyFunctionDecl { visibility, purity, where_clause, + kind, .. } = decl; TyFunctionDecl { @@ -314,6 +332,11 @@ impl TyFunctionDecl { type_parameters: Default::default(), where_clause: where_clause.clone(), is_trait_method_dummy: false, + kind: match kind { + FunctionDeclarationKind::Default => TyFunctionDeclKind::Default, + FunctionDeclarationKind::Entry => TyFunctionDeclKind::Entry, + FunctionDeclarationKind::Test => TyFunctionDeclKind::Test, + }, } } @@ -385,14 +408,13 @@ impl TyFunctionDecl { } /// Whether or not this function is the default entry point. - pub fn is_main_entry(&self) -> bool { - // NOTE: We may want to make this check more sophisticated or customisable in the future, - // but for now this assumption is baked in throughout the compiler. - self.name.as_str() == sway_types::constants::DEFAULT_ENTRY_POINT_FN_NAME + pub fn is_entry(&self) -> bool { + matches!(self.kind, TyFunctionDeclKind::Entry) } /// Whether or not this function is a unit test, i.e. decorated with `#[test]`. pub fn is_test(&self) -> bool { + //TODO match kind to Test self.attributes .contains_key(&transform::AttributeKind::Test) } @@ -414,8 +436,8 @@ impl TyFunctionDecl { } /// Whether or not this function describes a program entry point. - pub fn is_entry(&self) -> bool { - self.is_main_entry() || self.is_test() + pub fn is_entry_or_test(&self) -> bool { + self.is_entry() || self.is_test() } /// Whether or not this function is a constructor for the type given by `type_id`. diff --git a/sway-core/src/language/ty/declaration/impl_trait.rs b/sway-core/src/language/ty/declaration/impl_trait.rs index f8cddea7f05..69a0adc14dc 100644 --- a/sway-core/src/language/ty/declaration/impl_trait.rs +++ b/sway-core/src/language/ty/declaration/impl_trait.rs @@ -22,6 +22,12 @@ pub struct TyImplTrait { pub span: Span, } +impl TyImplTrait { + pub fn is_impl_contract(&self, te: &TypeEngine) -> bool { + matches!(&*te.get(self.implementing_for.type_id), TypeInfo::Contract) + } +} + impl Named for TyImplTrait { fn name(&self) -> &Ident { &self.trait_name.suffix diff --git a/sway-core/src/language/ty/expression/expression_variant.rs b/sway-core/src/language/ty/expression/expression_variant.rs index ccb672012d0..6aa7b320752 100644 --- a/sway-core/src/language/ty/expression/expression_variant.rs +++ b/sway-core/src/language/ty/expression/expression_variant.rs @@ -25,7 +25,6 @@ pub enum TyExpressionVariant { Literal(Literal), FunctionApplication { call_path: CallPath, - contract_call_params: IndexMap, arguments: Vec<(Ident, TyExpression)>, fn_ref: DeclRefFunction, selector: Option, @@ -35,6 +34,8 @@ pub enum TyExpressionVariant { call_path_typeid: Option, /// This tracks whether monomorphization has been deferred between compiler stages. deferred_monomorphization: bool, + contract_call_params: IndexMap, + contract_caller: Option>, }, LazyOperator { op: LazyOp, @@ -447,6 +448,7 @@ impl HashWithEngines for TyExpressionVariant { type_binding: _, call_path_typeid: _, deferred_monomorphization: _, + .. } => { call_path.hash(state); fn_ref.hash(state, engines); diff --git a/sway-core/src/language/ty/module.rs b/sway-core/src/language/ty/module.rs index 876635669a9..b3b5c44d2f1 100644 --- a/sway-core/src/language/ty/module.rs +++ b/sway-core/src/language/ty/module.rs @@ -72,6 +72,16 @@ impl TyModule { }) } + /// All contract functions within this module. + pub fn contract_fns<'a: 'b, 'b>( + &'b self, + engines: &'a Engines, + ) -> impl '_ + Iterator { + self.all_nodes + .iter() + .flat_map(move |node| node.contract_fns(engines)) + } + pub(crate) fn check_deprecated( &self, engines: &Engines, diff --git a/sway-core/src/language/ty/program.rs b/sway-core/src/language/ty/program.rs index daa66cb3cb9..faa8d0c6015 100644 --- a/sway-core/src/language/ty/program.rs +++ b/sway-core/src/language/ty/program.rs @@ -7,7 +7,7 @@ use crate::{ transform::AllowDeprecatedState, type_system::*, types::*, - Engines, + Engines, ExperimentalFlags, }; use sway_error::{ @@ -52,6 +52,7 @@ impl TyProgram { root: &TyModule, kind: parsed::TreeType, package_name: &str, + experimental: ExperimentalFlags, ) -> Result<(TyProgramKind, Vec, Vec), ErrorEmitted> { // Extract program-kind-specific properties from the root nodes. @@ -68,13 +69,14 @@ impl TyProgram { &submodule.module, parsed::TreeType::Library, package_name, + experimental, ) { Ok(_) => {} Err(_) => continue, } } - let mut mains = Vec::new(); + let mut entries = Vec::new(); let mut declarations = Vec::::new(); let mut abi_entries = Vec::new(); let mut fn_declarations = std::collections::HashSet::new(); @@ -89,8 +91,8 @@ impl TyProgram { })) => { let func = decl_engine.get_function(decl_id); - if func.name.as_str() == "main" { - mains.push(*decl_id); + if matches!(func.kind, TyFunctionDeclKind::Entry) { + entries.push(*decl_id); } if !fn_declarations.insert(func.name.clone()) { @@ -178,7 +180,7 @@ impl TyProgram { if kind != parsed::TreeType::Contract { // impure functions are disallowed in non-contracts if !matches!(kind, parsed::TreeType::Library { .. }) { - for err in disallow_impure_functions(decl_engine, &declarations, &mains) { + for err in disallow_impure_functions(decl_engine, &declarations, &entries) { handler.emit_err(err); } } @@ -230,7 +232,15 @@ impl TyProgram { } } - TyProgramKind::Contract { abi_entries } + TyProgramKind::Contract { + entry_function: if experimental.new_encoding { + assert!(entries.len() == 1); + Some(entries[0]) + } else { + None + }, + abi_entries, + } } parsed::TreeType::Library => { if !configurables.is_empty() { @@ -244,19 +254,19 @@ impl TyProgram { } parsed::TreeType::Predicate => { // A predicate must have a main function and that function must return a boolean. - if mains.is_empty() { + if entries.is_empty() { return Err( handler.emit_err(CompileError::NoPredicateMainFunction(root.span.clone())) ); } - if mains.len() > 1 { - let mains_last = decl_engine.get_function(mains.last().unwrap()); + if entries.len() > 1 { + let mains_last = decl_engine.get_function(entries.last().unwrap()); handler.emit_err(CompileError::MultipleDefinitionsOfFunction { name: mains_last.name.clone(), span: mains_last.name.span(), }); } - let main_func_id = mains.remove(0); + let main_func_id = entries.remove(0); let main_func = decl_engine.get_function(&main_func_id); match &*ty_engine.get(main_func.return_type.type_id) { TypeInfo::Boolean => (), @@ -267,19 +277,19 @@ impl TyProgram { } } TyProgramKind::Predicate { - main_function: main_func_id, + entry_function: main_func_id, } } parsed::TreeType::Script => { // A script must have exactly one main function - if mains.is_empty() { + if entries.is_empty() { return Err( handler.emit_err(CompileError::NoScriptMainFunction(root.span.clone())) ); } - if mains.len() > 1 { - let mains_last = decl_engine.get_function(mains.last().unwrap()); + if entries.len() > 1 { + let mains_last = decl_engine.get_function(entries.last().unwrap()); handler.emit_err(CompileError::MultipleDefinitionsOfFunction { name: mains_last.name.clone(), span: mains_last.name.span(), @@ -289,7 +299,7 @@ impl TyProgram { // A script must not return a `raw_ptr` or any type aggregating a `raw_slice`. // Directly returning a `raw_slice` is allowed, which will be just mapped to a RETD. // TODO: Allow returning nested `raw_slice`s when our spec supports encoding DSTs. - let main_func_decl_id = mains.remove(0); + let main_func_decl_id = entries.remove(0); let main_func = decl_engine.get_function(&main_func_decl_id); for p in main_func.parameters() { @@ -336,14 +346,20 @@ impl TyProgram { } TyProgramKind::Script { - main_function: main_func_decl_id, + entry_function: main_func_decl_id, } } }; // check if no ref mut arguments passed to a `main()` in a `script` or `predicate`. match &typed_program_kind { - TyProgramKind::Script { main_function, .. } - | TyProgramKind::Predicate { main_function, .. } => { + TyProgramKind::Script { + entry_function: main_function, + .. + } + | TyProgramKind::Predicate { + entry_function: main_function, + .. + } => { let main_function = decl_engine.get_function(main_function); for param in &main_function.parameters { if param.is_reference && param.is_mutable { @@ -429,14 +445,28 @@ impl CollectTypesMetadata for TyProgram { match &self.kind { // For scripts and predicates, collect metadata for all the types starting with // `main()` as the only entry point - TyProgramKind::Script { main_function, .. } - | TyProgramKind::Predicate { main_function, .. } => { + TyProgramKind::Script { + entry_function: main_function, + .. + } + | TyProgramKind::Predicate { + entry_function: main_function, + .. + } => { let main_function = decl_engine.get_function(main_function); metadata.append(&mut main_function.collect_types_metadata(handler, ctx)?); } // For contracts, collect metadata for all the types starting with each ABI method as // an entry point. - TyProgramKind::Contract { abi_entries, .. } => { + TyProgramKind::Contract { + abi_entries, + entry_function: main_function, + } => { + if let Some(main_function) = main_function { + let entry = decl_engine.get_function(main_function); + metadata.append(&mut entry.collect_types_metadata(handler, ctx)?); + } + for entry in abi_entries.iter() { let entry = decl_engine.get_function(entry); metadata.append(&mut entry.collect_types_metadata(handler, ctx)?); @@ -494,16 +524,17 @@ impl CollectTypesMetadata for TyProgram { #[derive(Clone, Debug)] pub enum TyProgramKind { Contract { + entry_function: Option>, abi_entries: Vec>, }, Library { name: String, }, Predicate { - main_function: DeclId, + entry_function: DeclId, }, Script { - main_function: DeclId, + entry_function: DeclId, }, } diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index 8c238d3dbaf..a30d2b92660 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -109,7 +109,7 @@ pub fn parse( parse_module, }| { let lexed = lexed::LexedProgram { - kind: kind.clone(), + kind, root: lexed_module, }; let parsed = parsed::ParseProgram { @@ -212,7 +212,7 @@ fn parse_in_memory( hash, }; let lexed_program = lexed::LexedProgram::new( - kind.clone(), + kind, lexed::LexedModule { tree: module.value, submodules: Default::default(), diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs index f60e85e9931..470778228c0 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs @@ -1,875 +1,660 @@ use crate::{ - decl_engine::{parsed_engine::ParsedDeclEngineInsert, DeclEngineGet}, + decl_engine::{DeclEngineGet, DeclId, DeclRef}, language::{ - parsed::{ - AstNode, AstNodeContent, CodeBlock, Declaration, Expression, ExpressionKind, - FunctionDeclaration, FunctionParameter, ImplItem, ImplTrait, MatchBranch, - MatchExpression, MethodApplicationExpression, MethodName, Scrutinee, - SubfieldExpression, - }, - ty::{self, TyAstNode, TyDecl}, - CallPath, QualifiedCallPath, + parsed::{self, AstNodeContent, Declaration, FunctionDeclarationKind}, + ty::{self, TyAstNode, TyDecl, TyEnumDecl, TyFunctionDecl, TyStructDecl}, + Purity, }, - semantic_analysis::{type_check_context::EnforceTypeArguments, TypeCheckContext}, - transform::AttributesMap, - Engines, TraitConstraint, TypeArgs, TypeArgument, TypeBinding, TypeId, TypeInfo, TypeParameter, + semantic_analysis::TypeCheckContext, + Engines, TypeId, TypeInfo, TypeParameter, }; +use itertools::Itertools; use sway_error::handler::Handler; -use sway_types::{Ident, Span}; +use sway_parse::Parse; +use sway_types::{integer_bits::IntegerBits, BaseIdent, Named, Span}; /// Contains all information needed to implement AbiEncode -pub struct AutoImplAbiEncodeContext<'a, 'b> { +pub struct AutoImplAbiEncodeContext<'a, 'b> +where + 'a: 'b, +{ ctx: &'b mut TypeCheckContext<'a>, - buffer_type_id: TypeId, - abi_encode_call_path: CallPath, } -impl<'a, 'b> AutoImplAbiEncodeContext<'a, 'b> { - /// This function fails if the context does not have access to the "core" module +impl<'a, 'b> AutoImplAbiEncodeContext<'a, 'b> +where + 'a: 'b, +{ pub fn new(ctx: &'b mut TypeCheckContext<'a>) -> Option { - let buffer_type_id = Self::resolve_core_codec_buffer(ctx)?; - Some(Self { - ctx, - buffer_type_id, - abi_encode_call_path: CallPath::absolute(&["core", "codec", "AbiEncode"]), - }) + Some(Self { ctx }) } - fn resolve_core_codec_buffer(ctx: &mut TypeCheckContext<'_>) -> Option { - let handler = Handler::default(); - let buffer_type_id = ctx.engines.te().insert( - ctx.engines, - TypeInfo::Custom { - qualified_call_path: QualifiedCallPath { - call_path: CallPath::absolute(&["core", "codec", "Buffer"]), - qualified_path_root: None, - }, - type_arguments: None, - root_type_id: None, - }, - None, - ); - let buffer_type_id = ctx - .resolve_type( - &handler, - buffer_type_id, - &Span::dummy(), - EnforceTypeArguments::No, - None, - ) - .ok()?; - Some(buffer_type_id) - } + pub fn parse(input: &str) -> T + where + T: Parse, + { + // println!("[{}]", input); + let handler = <_>::default(); + let ts = + sway_parse::lex(&handler, &std::sync::Arc::from(input), 0, input.len(), None).unwrap(); + let mut p = sway_parse::Parser::new(&handler, &ts); + p.check_double_underscore = false; - fn import_core_codec(&mut self) -> bool { - // Check if the compilation context has acces to the - // core library. - let handler = Handler::default(); - let _ = self.ctx.star_import( - &handler, - &[ - Ident::new_no_span("core".into()), - Ident::new_no_span("codec".into()), - ], - true, - ); + let r = p.parse(); - !handler.has_errors() - } + assert!(!handler.has_errors(), "{:?}", handler); + assert!(!handler.has_warnings(), "{:?}", handler); - /// Verify with a enum has all variants that can be auto implemented. - fn can_enum_auto_impl_abi_encode(&mut self, decl: &ty::TyDecl) -> bool { - let handler = Handler::default(); - let Ok(enum_decl) = decl - .to_enum_ref(&handler, self.ctx.engines()) - .map(|enum_ref| self.ctx.engines().de().get(enum_ref.id())) - else { - return false; - }; + assert!(!p.has_errors()); + assert!(!p.has_warnings()); - let all_variants_are_abi_encode = enum_decl.variants.iter().all(|variant| { - // If the variant is the generic argument of the enum, we are ok - // because we will constraint it later - if self - .ctx - .engines() - .te() - .get(variant.type_argument.type_id) - .is_unknown_generic() - { - return true; - } + r.unwrap() + } - // Check variant implements AbiEncode - self.ctx.check_type_impls_traits( - variant.type_argument.type_id, - &[TraitConstraint { - trait_name: self.abi_encode_call_path.clone(), - type_arguments: vec![], - }], + fn generate_type_parameters_declaration_code( + &self, + type_parameters: &[TypeParameter], + ) -> String { + if type_parameters.is_empty() { + String::new() + } else { + format!( + "<{}>", + itertools::intersperse( + type_parameters.iter().map(|x| { x.name_ident.as_str() }), + ", " + ) + .collect::() ) - }); + } + } + + fn generate_type_parameters_constraints_code( + &self, + type_parameters: &[TypeParameter], + extra_constraint: &str, + ) -> String { + let mut code = String::new(); + + for t in type_parameters.iter() { + code.push_str(&format!( + "{}: {},\n", + t.name_ident.as_str(), + itertools::intersperse( + [extra_constraint].into_iter().chain( + t.trait_constraints + .iter() + .map(|x| x.trait_name.suffix.as_str()) + ), + " + " + ) + .collect::() + )); + } + + if !code.is_empty() { + code = format!(" where {code}\n"); + } - all_variants_are_abi_encode + code } - /// Auto implements AbiEncode for structs - fn enum_auto_impl_abi_encode(&mut self, engines: &Engines, decl: &TyDecl) -> Option { - if !self.can_enum_auto_impl_abi_encode(decl) { - return None; + fn generate_abi_encode_code( + &self, + name: &BaseIdent, + type_parameters: &[TypeParameter], + body: String, + ) -> String { + let type_parameters_declaration = + self.generate_type_parameters_declaration_code(type_parameters); + let type_parameters_constraints = + self.generate_type_parameters_constraints_code(type_parameters, "AbiEncode"); + + let name = name.as_str(); + + if body.is_empty() { + format!("#[allow(dead_code)] impl{type_parameters_declaration} AbiEncode for {name}{type_parameters_declaration}{type_parameters_constraints} {{ + #[allow(dead_code)] + fn abi_encode(self, ref mut _buffer: Buffer) {{ + }} + }}") + } else { + format!("#[allow(dead_code)] impl{type_parameters_declaration} AbiEncode for {name}{type_parameters_declaration}{type_parameters_constraints} {{ + #[allow(dead_code)] + fn abi_encode(self, ref mut buffer: Buffer) {{ + {body} + }} + }}") } + } + + fn generate_abi_decode_code( + &self, + name: &BaseIdent, + type_parameters: &[TypeParameter], + body: String, + ) -> String { + let type_parameters_declaration = + self.generate_type_parameters_declaration_code(type_parameters); + let type_parameters_constraints = + self.generate_type_parameters_constraints_code(type_parameters, "AbiDecode"); + + let name = name.as_str(); + + if body == "Self { }" { + format!("#[allow(dead_code)] impl{type_parameters_declaration} AbiDecode for {name}{type_parameters_declaration}{type_parameters_constraints} {{ + #[allow(dead_code)] + fn abi_decode(ref mut _buffer: BufferReader) -> Self {{ + {body} + }} + }}") + } else { + format!("#[allow(dead_code)] impl{type_parameters_declaration} AbiDecode for {name}{type_parameters_declaration}{type_parameters_constraints} {{ + #[allow(dead_code)] + fn abi_decode(ref mut buffer: BufferReader) -> Self {{ + {body} + }} + }}") + } + } - let implementing_for_decl_ref = decl.get_enum_decl_ref().unwrap(); + fn generate_abi_encode_struct_body(&self, _engines: &Engines, decl: &TyStructDecl) -> String { + let mut code = String::new(); - let unit_type_id = - self.ctx - .engines - .te() - .insert(self.ctx.engines, TypeInfo::Tuple(vec![]), None); + for f in decl.fields.iter() { + code.push_str(&format!( + "self.{field_name}.abi_encode(buffer);\n", + field_name = f.name.as_str(), + )); + } - let enum_decl = self.ctx.engines().de().get(implementing_for_decl_ref.id()); + code + } - if !self.import_core_codec() { - return None; + fn generate_abi_decode_struct_body(&self, engines: &Engines, decl: &TyStructDecl) -> String { + let mut code = String::new(); + for f in decl.fields.iter() { + code.push_str(&format!( + "{field_name}: buffer.decode::<{field_type_name}>(),", + field_name = f.name.as_str(), + field_type_name = Self::generate_type(engines, f.type_argument.type_id), + )); } - // If the enum has generic parameters, they must have AbiEncode appended - // as new constraint - let impl_type_parameters: Vec<_> = enum_decl - .type_parameters - .iter() - .map(|type_parameter| { - let type_id = self.ctx.engines.te().insert( - self.ctx.engines(), - TypeInfo::Custom { - qualified_call_path: QualifiedCallPath { - call_path: CallPath { - prefixes: vec![], - suffix: Ident::new_no_span( - type_parameter.name_ident.as_str().into(), - ), - is_absolute: false, - }, - qualified_path_root: None, - }, - type_arguments: None, - root_type_id: None, - }, - None, - ); - - let mut trait_constraints: Vec<_> = type_parameter - .trait_constraints - .iter() - .map(|x| TraitConstraint { - trait_name: CallPath { - prefixes: vec![], - suffix: Ident::new_no_span(x.trait_name.suffix.as_str().into()), - is_absolute: false, - }, - type_arguments: x - .type_arguments - .iter() - .map(|x| { - let name = match &*self.ctx.engines.te().get(x.type_id) { - TypeInfo::Custom { - qualified_call_path, - .. - } => Ident::new_no_span( - qualified_call_path.call_path.suffix.as_str().into(), - ), - _ => todo!(), - }; - - let type_id = self.ctx.engines.te().insert( - self.ctx.engines(), - TypeInfo::Custom { - qualified_call_path: QualifiedCallPath { - call_path: CallPath { - prefixes: vec![], - suffix: name, - is_absolute: false, - }, - qualified_path_root: None, - }, - type_arguments: None, - root_type_id: None, - }, - None, - ); - - TypeArgument { - type_id, - initial_type_id: type_id, - span: Span::dummy(), - call_path_tree: None, - } - }) - .collect(), - }) - .collect(); - - trait_constraints.push(TraitConstraint { - trait_name: CallPath { - prefixes: vec![], - suffix: Ident::new_no_span("AbiEncode".into()), - is_absolute: false, - }, - type_arguments: vec![], - }); - - TypeParameter { - type_id, - initial_type_id: type_id, - name_ident: Ident::new_no_span(type_parameter.name_ident.as_str().into()), - trait_constraints, - trait_constraints_span: Span::dummy(), - is_from_parent: false, + format!("Self {{ {code} }}") + } + + fn generate_abi_decode_enum_body(&self, engines: &Engines, decl: &TyEnumDecl) -> String { + let enum_name = decl.call_path.suffix.as_str(); + let arms = decl.variants.iter() + .map(|x| { + let name = x.name.as_str(); + if engines.te().get(x.type_argument.type_id).is_unit() { + format!("{} => {}::{}, \n", x.tag, enum_name, name) + } else { + let variant_type_name = Self::generate_type(engines, x.type_argument.type_id); + format!("{tag_value} => {enum_name}::{variant_name}(buffer.decode::<{variant_type}>()), \n", + tag_value = x.tag, + enum_name = enum_name, + variant_name = name, + variant_type = variant_type_name + ) } }) - .collect(); + .collect::(); - let implementing_for_type_id = self.ctx.engines.te().insert( - self.ctx.engines, - TypeInfo::Custom { - qualified_call_path: QualifiedCallPath { - call_path: CallPath { - prefixes: vec![], - suffix: enum_decl.call_path.suffix.clone(), - is_absolute: false, - }, - qualified_path_root: None, - }, - type_arguments: if impl_type_parameters.is_empty() { - None + use std::fmt::Write; + let mut code = String::new(); + writeln!(&mut code, "let variant: u64 = buffer.decode::();").unwrap(); + writeln!(&mut code, "match variant {{ {arms} _ => __revert(0), }}").unwrap(); + + code + } + + fn generate_abi_encode_enum_body(&self, engines: &Engines, decl: &TyEnumDecl) -> String { + let enum_name = decl.call_path.suffix.as_str(); + let arms = decl + .variants + .iter() + .map(|x| { + let name = x.name.as_str(); + if engines.te().get(x.type_argument.type_id).is_unit() { + format!( + "{enum_name}::{variant_name} => {{ + {tag_value}u64.abi_encode(buffer); + }}, \n", + tag_value = x.tag, + enum_name = enum_name, + variant_name = name + ) } else { - Some( - impl_type_parameters - .iter() - .map(|x| { - let type_id = self.ctx.engines().te().insert( - self.ctx.engines(), - TypeInfo::Custom { - qualified_call_path: QualifiedCallPath { - call_path: CallPath { - prefixes: vec![], - suffix: x.name_ident.clone(), - is_absolute: false, - }, - qualified_path_root: None, - }, - type_arguments: None, - root_type_id: None, - }, - None, - ); - - TypeArgument { - type_id, - initial_type_id: type_id, - span: Span::dummy(), - call_path_tree: None, - } - }) - .collect(), + format!( + "{enum_name}::{variant_name}(value) => {{ + {tag_value}u64.abi_encode(buffer); + value.abi_encode(buffer); + }}, \n", + tag_value = x.tag, + enum_name = enum_name, + variant_name = name, ) - }, - root_type_id: None, - }, - None, + } + }) + .collect::(); + + format!("match self {{ {arms} }}") + } + + pub fn parse_item_fn_to_typed_ast_node( + &mut self, + engines: &Engines, + kind: FunctionDeclarationKind, + code: &str, + ) -> Option { + let mut ctx = crate::transform::to_parsed_lang::Context::new( + crate::BuildTarget::Fuel, + self.ctx.experimental, ); - let implementing_for = TypeArgument { - type_id: implementing_for_type_id, - initial_type_id: implementing_for_type_id, - span: Span::dummy(), - call_path_tree: None, - }; + let handler = Handler::default(); - let impl_trait_item = FunctionDeclaration { - purity: crate::language::Purity::Pure, - attributes: AttributesMap::default(), - name: Ident::new_no_span("abi_encode".into()), - visibility: crate::language::Visibility::Public, - body: CodeBlock { - contents: vec![ - AstNode { - content: AstNodeContent::Expression( - Expression { - kind: ExpressionKind::Match( - MatchExpression { - value: Box::new(Expression { - kind: ExpressionKind::AmbiguousVariableExpression ( - Ident::new_no_span("self".into()) - ), - span: Span::dummy() - }), - branches: enum_decl.variants.iter() - .enumerate() - .map(|(i, x)| { - let variant_type = self.ctx.engines().te().get(x.type_argument.type_id); - MatchBranch { - scrutinee: Scrutinee::EnumScrutinee { - call_path: CallPath { - prefixes: vec![ - Ident::new_no_span("Self".into()) - ], - suffix: Ident::new_no_span( - x.name.as_str().into() - ), - is_absolute: false - }, - value: Box::new(if variant_type.is_unit() { - Scrutinee::CatchAll { - span: Span::dummy() - } - } else { - Scrutinee::Variable { - name: Ident::new_no_span("x".into()), - span: Span::dummy() - } - }), - span: Span::dummy(), - }, - result: Expression { - kind: ExpressionKind::CodeBlock( - CodeBlock { - contents: { - let mut contents = vec![]; - - // discriminant - contents.push( - AstNode { - content: AstNodeContent::Expression( - Expression { - kind: ExpressionKind::MethodApplication( - Box::new(MethodApplicationExpression { - method_name_binding: TypeBinding { - inner: MethodName::FromModule { - method_name: Ident::new_no_span("abi_encode".into()) - }, - type_arguments: TypeArgs::Regular(vec![]), - span: Span::dummy() - }, - arguments: vec![ - Expression { - kind: ExpressionKind::Literal( - crate::language::Literal::U64( - i as u64 - ) - ), - span: Span::dummy() - }, - Expression { - kind: ExpressionKind::AmbiguousVariableExpression( - Ident::new_no_span("buffer".into()) - ), - span: Span::dummy() - } - ], - contract_call_params: vec![], - }) - ), - span: Span::dummy() - } - ), - span: Span::dummy() - }); - - // variant data - if !variant_type.is_unit() { - contents.push( - AstNode { - content: AstNodeContent::Expression( - Expression { - kind: ExpressionKind::MethodApplication( - Box::new(MethodApplicationExpression { - method_name_binding: TypeBinding { - inner: MethodName::FromModule { - method_name: Ident::new_no_span("abi_encode".into()) - }, - type_arguments: TypeArgs::Regular(vec![]), - span: Span::dummy() - }, - arguments: vec![ - Expression { - kind: ExpressionKind::AmbiguousVariableExpression ( - Ident::new_no_span("x".into()) - ), - span: Span::dummy() - }, - Expression { - kind: ExpressionKind::AmbiguousVariableExpression( - Ident::new_no_span("buffer".into()) - ), - span: Span::dummy() - } - ], - contract_call_params: vec![], - }) - ), - span: Span::dummy() - } - ), - span: Span::dummy() - } - ); - } - - contents - }, - whole_block_span: Span::dummy() - } - ), - span: Span::dummy() - }, - span: Span::dummy() - } - }).collect() - } - ), - span: Span::dummy() - } - ), - span: Span::dummy() - } - ], - whole_block_span: Span::dummy(), - }, - parameters: vec![ - FunctionParameter { - name: Ident::new_no_span("self".into()), - is_reference: false, - is_mutable: false, - mutability_span: Span::dummy(), - type_argument: TypeArgument { - type_id: implementing_for_type_id, - initial_type_id: implementing_for_type_id, - span: Span::dummy(), - call_path_tree: None, - }, - }, - FunctionParameter { - name: Ident::new_no_span("buffer".into()), - is_reference: true, - is_mutable: true, - mutability_span: Span::dummy(), - type_argument: TypeArgument { - type_id: self.buffer_type_id, - initial_type_id: self.buffer_type_id, - span: Span::dummy(), - call_path_tree: None, - }, - }, - ], - span: Span::dummy(), - return_type: TypeArgument { - type_id: unit_type_id, - initial_type_id: unit_type_id, - span: Span::dummy(), - call_path_tree: None, - }, - type_parameters: vec![], - where_clause: vec![], - }; - let impl_trait_item = engines.pe().insert(impl_trait_item); - - let impl_trait = ImplTrait { - impl_type_parameters, - trait_name: self.abi_encode_call_path.clone(), - trait_type_arguments: vec![], - implementing_for, - items: vec![ImplItem::Fn(impl_trait_item)], - block_span: Span::dummy(), + let item = Self::parse(code); + let nodes = crate::transform::to_parsed_lang::item_to_ast_nodes( + &mut ctx, + &handler, + engines, + item, + false, + None, + Some(kind), + ) + .unwrap(); + + let decl = match nodes[0].content { + AstNodeContent::Declaration(Declaration::FunctionDeclaration(f)) => f, + _ => todo!(), }; - let impl_trait = engines.pe().insert(impl_trait); - let impl_trait = Declaration::ImplTrait(impl_trait); - let handler = Handler::default(); - TyAstNode::type_check( + assert!(!handler.has_errors(), "{:?} {}", handler, code); + assert!(!handler.has_warnings(), "{:?}", handler); + + let ctx = self.ctx.by_ref(); + let decl = TyDecl::type_check( &handler, - self.ctx.by_ref(), - AstNode { - content: AstNodeContent::Declaration(impl_trait), - span: Span::dummy(), - }, + ctx, + parsed::Declaration::FunctionDeclaration(decl), ) - .ok() + .unwrap(); + + assert!(!handler.has_errors(), "{:?} {}", handler, code); + assert!(!handler.has_warnings(), "{:?}", handler); + + Some(TyAstNode { + content: ty::TyAstNodeContent::Declaration(decl), + span: Span::dummy(), + }) } - // Check if a struct can implement AbiEncode - fn can_struct_auto_impl_abi_encode(&mut self, decl: &TyDecl) -> bool { - // skip module "core" - // Because of ordering, we cannot guarantee auto impl - // for structs inside "core" - if matches!(self.ctx.namespace().root_module_name(), Some(x) if x.as_str() == "core") { - return false; - } + fn parse_item_impl_to_typed_ast_node( + &mut self, + engines: &Engines, + code: &str, + ) -> Option { + let mut ctx = crate::transform::to_parsed_lang::Context::new( + crate::BuildTarget::Fuel, + self.ctx.experimental, + ); - let Some(decl_ref) = decl.get_struct_decl_ref() else { - return false; - }; - let struct_ref = self.ctx.engines().de().get(decl_ref.id()); + let handler = Handler::default(); - // Do not support types with generic constraints - // because this generates a circular impl trait - if struct_ref.type_parameters.iter().any(|x| { - x.trait_constraints - .iter() - .any(|c| !c.type_arguments.is_empty()) - }) { - return false; - } + let item = Self::parse(code); + let nodes = crate::transform::to_parsed_lang::item_to_ast_nodes( + &mut ctx, &handler, engines, item, false, None, None, + ) + .unwrap(); - let all_fields_are_abi_encode = struct_ref.fields.iter().all(|field| { - if let TypeInfo::UnknownGeneric { .. } = - &*self.ctx.engines().te().get(field.type_argument.type_id) - { - return true; - } + let decl = match nodes[0].content { + AstNodeContent::Declaration(Declaration::ImplTrait(f)) => f, + _ => todo!(), + }; - let handler = Handler::default(); - let engines = self.ctx.engines; - self.ctx - .namespace_mut() - .module_mut() - .current_items_mut() - .implemented_traits - .check_if_trait_constraints_are_satisfied_for_type( - &handler, - field.type_argument.type_id, - &[TraitConstraint { - trait_name: CallPath { - prefixes: vec![ - Ident::new_no_span("core".into()), - Ident::new_no_span("codec".into()), - ], - suffix: Ident::new_no_span("AbiEncode".into()), - is_absolute: true, - }, - type_arguments: vec![], - }], - &Span::dummy(), - engines, - crate::namespace::TryInsertingTraitImplOnFailure::Yes, - ) - .is_ok() - }); + assert!(!handler.has_errors(), "{:?}", handler); + + let ctx = self.ctx.by_ref(); + let decl = TyDecl::type_check(&handler, ctx, Declaration::ImplTrait(decl)).unwrap(); - all_fields_are_abi_encode + if handler.has_errors() { + None + } else { + Some(TyAstNode { + content: ty::TyAstNodeContent::Declaration(decl), + span: Span::dummy(), + }) + } } - // Auto implements AbiEncode for structs - fn struct_auto_impl_abi_encode( + // Auto implements AbiEncode and AbiDecode for structs and returns their `AstNode`s. + fn auto_impl_struct( &mut self, engines: &Engines, decl: &TyDecl, - ) -> Option { - if !self.can_struct_auto_impl_abi_encode(decl) { - return None; + ) -> (Option, Option) { + if matches!(self.ctx.namespace.root().module.name.as_ref(), Some(x) if x.as_str() == "core") + { + return (None, None); } let implementing_for_decl_ref = decl.get_struct_decl_ref().unwrap(); let struct_decl = self.ctx.engines().de().get(implementing_for_decl_ref.id()); - let unit_type_id = - self.ctx - .engines - .te() - .insert(self.ctx.engines, TypeInfo::Tuple(vec![]), None); - - let import_handler = Handler::default(); - let _ = self.ctx.star_import( - &import_handler, - &[ - Ident::new_no_span("core".into()), - Ident::new_no_span("codec".into()), - ], - true, + let abi_encode_body = self.generate_abi_encode_struct_body(engines, &struct_decl); + let abi_encode_code = self.generate_abi_encode_code( + struct_decl.name(), + &struct_decl.type_parameters, + abi_encode_body, ); + let abi_encode_node = self.parse_item_impl_to_typed_ast_node(engines, &abi_encode_code); - if import_handler.has_errors() { - return None; + let abi_decode_body = self.generate_abi_decode_struct_body(engines, &struct_decl); + let abi_decode_code = self.generate_abi_decode_code( + struct_decl.name(), + &struct_decl.type_parameters, + abi_decode_body, + ); + let abi_decode_node = self.parse_item_impl_to_typed_ast_node(engines, &abi_decode_code); + + (abi_encode_node, abi_decode_node) + } + + fn auto_impl_enum( + &mut self, + engines: &Engines, + decl: &TyDecl, + ) -> (Option, Option) { + if matches!(self.ctx.namespace.root().module.name.as_ref(), Some(x) if x.as_str() == "core") + { + return (None, None); } - let abi_encode_trait_name = CallPath { - prefixes: vec![ - Ident::new_no_span("core".into()), - Ident::new_no_span("codec".into()), - ], - suffix: Ident::new_no_span("AbiEncode".into()), - is_absolute: true, - }; + let enum_decl_ref = decl.get_enum_decl_ref().unwrap(); + let enum_decl = self.ctx.engines().de().get(enum_decl_ref.id()); - let impl_type_parameters: Vec<_> = struct_decl - .type_parameters - .iter() - .map(|x| { - let type_id = self.ctx.engines.te().insert( - self.ctx.engines(), - TypeInfo::Custom { - qualified_call_path: QualifiedCallPath { - call_path: CallPath { - prefixes: vec![], - suffix: Ident::new_no_span(x.name_ident.as_str().into()), - is_absolute: false, - }, - qualified_path_root: None, - }, - type_arguments: None, - root_type_id: None, - }, - None, - ); - - let mut trait_constraints: Vec<_> = x - .trait_constraints - .iter() - .map(|x| TraitConstraint { - trait_name: CallPath { - prefixes: vec![], - suffix: Ident::new_no_span(x.trait_name.suffix.as_str().into()), - is_absolute: false, - }, - type_arguments: x - .type_arguments - .iter() - .map(|x| { - let name = match &*self.ctx.engines.te().get(x.type_id) { - TypeInfo::Custom { - qualified_call_path, - .. - } => Ident::new_no_span( - qualified_call_path.call_path.suffix.as_str().into(), - ), - _ => todo!(), - }; - - let type_id = self.ctx.engines.te().insert( - self.ctx.engines(), - TypeInfo::Custom { - qualified_call_path: QualifiedCallPath { - call_path: CallPath { - prefixes: vec![], - suffix: name, - is_absolute: false, - }, - qualified_path_root: None, - }, - type_arguments: None, - root_type_id: None, - }, - None, - ); - - TypeArgument { - type_id, - initial_type_id: type_id, - span: Span::dummy(), - call_path_tree: None, - } - }) - .collect(), - }) - .collect(); - trait_constraints.push(TraitConstraint { - trait_name: CallPath { - prefixes: vec![], - suffix: Ident::new_no_span("AbiEncode".into()), - is_absolute: false, - }, - type_arguments: vec![], - }); - - TypeParameter { - type_id, - initial_type_id: type_id, - name_ident: Ident::new_no_span(x.name_ident.as_str().into()), - trait_constraints, - trait_constraints_span: Span::dummy(), - is_from_parent: false, - } - }) - .collect(); + let abi_decode_body = self.generate_abi_encode_enum_body(engines, &enum_decl); + let abi_decode_code = self.generate_abi_encode_code( + enum_decl.name(), + &enum_decl.type_parameters, + abi_decode_body, + ); + let abi_encode_node = self.parse_item_impl_to_typed_ast_node(engines, &abi_decode_code); + + let abi_decode_body = self.generate_abi_decode_enum_body(engines, &enum_decl); + let abi_decode_code = self.generate_abi_decode_code( + enum_decl.name(), + &enum_decl.type_parameters, + abi_decode_body, + ); + let abi_decode_node = self.parse_item_impl_to_typed_ast_node(engines, &abi_decode_code); + + (abi_encode_node, abi_decode_node) + } - let implementing_for_type_id = self.ctx.engines.te().insert( - self.ctx.engines, + pub fn generate( + &mut self, + engines: &Engines, + decl: &ty::TyDecl, + ) -> (Option, Option) { + match decl { + TyDecl::StructDecl(_) => self.auto_impl_struct(engines, decl), + TyDecl::EnumDecl(_) => self.auto_impl_enum(engines, decl), + _ => (None, None), + } + } + + fn generate_type(engines: &Engines, type_id: TypeId) -> String { + match &*engines.te().get(type_id) { + TypeInfo::UnknownGeneric { name, .. } => name.to_string(), + TypeInfo::Placeholder(type_param) => type_param.name_ident.to_string(), + TypeInfo::StringSlice => "str".into(), + TypeInfo::StringArray(x) => format!("str[{}]", x.val()), + TypeInfo::UnsignedInteger(x) => match x { + IntegerBits::Eight => "u8", + IntegerBits::Sixteen => "u16", + IntegerBits::ThirtyTwo => "u32", + IntegerBits::SixtyFour => "u64", + IntegerBits::V256 => "u256", + } + .into(), + TypeInfo::Boolean => "bool".into(), TypeInfo::Custom { - qualified_call_path: QualifiedCallPath { - call_path: CallPath { - prefixes: vec![], - suffix: struct_decl.call_path.suffix.clone(), - is_absolute: false, - }, - qualified_path_root: None, - }, - type_arguments: if impl_type_parameters.is_empty() { - None + qualified_call_path: call_path, + .. + } => call_path.call_path.suffix.to_string(), + TypeInfo::Tuple(fields) => { + if fields.is_empty() { + return "()".into(); + } + let field_strs = fields + .iter() + .map(|field| Self::generate_type(engines, field.type_id)) + .collect::>(); + format!("({},)", field_strs.join(", ")) + } + TypeInfo::B256 => "b256".into(), + TypeInfo::Enum(decl_ref) => { + let decl = engines.de().get(decl_ref.id()); + + let type_parameters = decl + .type_parameters + .iter() + .map(|x| Self::generate_type(engines, x.type_id)) + .join(", "); + + let type_parameters = if !type_parameters.is_empty() { + format!("<{type_parameters}>") } else { - Some( - impl_type_parameters - .iter() - .map(|x| { - let type_id = self.ctx.engines().te().insert( - self.ctx.engines(), - TypeInfo::Custom { - qualified_call_path: QualifiedCallPath { - call_path: CallPath { - prefixes: vec![], - suffix: x.name_ident.clone(), - is_absolute: false, - }, - qualified_path_root: None, - }, - type_arguments: None, - root_type_id: None, - }, - None, - ); - - TypeArgument { - type_id, - initial_type_id: type_id, - span: Span::dummy(), - call_path_tree: None, - } - }) - .collect(), - ) - }, - root_type_id: None, - }, - None, - ); + type_parameters + }; - let implementing_for = TypeArgument { - type_id: implementing_for_type_id, - initial_type_id: implementing_for_type_id, - span: Span::dummy(), - call_path_tree: None, - }; + format!("{}{type_parameters}", decl.call_path.suffix.as_str()) + } + TypeInfo::Struct(decl_ref) => { + let decl = engines.de().get(decl_ref.id()); - let impl_trait_item = FunctionDeclaration { - purity: crate::language::Purity::Pure, - attributes: AttributesMap::default(), - name: Ident::new_no_span("abi_encode".into()), - visibility: crate::language::Visibility::Public, - body: CodeBlock { - contents: struct_decl - .fields + let type_parameters = decl + .type_parameters .iter() - .map(|x| AstNode { - content: AstNodeContent::Expression(Expression { - kind: ExpressionKind::MethodApplication(Box::new( - MethodApplicationExpression { - method_name_binding: TypeBinding { - inner: MethodName::FromModule { - method_name: Ident::new_no_span("abi_encode".into()), - }, - type_arguments: TypeArgs::Regular(vec![]), - span: Span::dummy(), - }, - arguments: vec![ - Expression { - kind: ExpressionKind::Subfield(SubfieldExpression { - prefix: Box::new(Expression { - kind: - ExpressionKind::AmbiguousVariableExpression( - Ident::new_no_span("self".into()), - ), - span: Span::dummy(), - }), - field_to_access: x.name.clone(), - }), - span: Span::dummy(), - }, - Expression { - kind: ExpressionKind::AmbiguousVariableExpression( - Ident::new_no_span("buffer".into()), - ), - span: Span::dummy(), - }, - ], - contract_call_params: vec![], - }, - )), - span: Span::dummy(), - }), - span: Span::dummy(), - }) - .collect(), - whole_block_span: Span::dummy(), - }, - parameters: vec![ - FunctionParameter { - name: Ident::new_no_span("self".into()), - is_reference: false, - is_mutable: false, - mutability_span: Span::dummy(), - type_argument: TypeArgument { - type_id: implementing_for_type_id, - initial_type_id: implementing_for_type_id, - span: Span::dummy(), - call_path_tree: None, - }, - }, - FunctionParameter { - name: Ident::new_no_span("buffer".into()), - is_reference: true, - is_mutable: true, - mutability_span: Span::dummy(), - type_argument: TypeArgument { - type_id: self.buffer_type_id, - initial_type_id: self.buffer_type_id, - span: Span::dummy(), - call_path_tree: None, - }, - }, - ], - span: Span::dummy(), - return_type: TypeArgument { - type_id: unit_type_id, - initial_type_id: unit_type_id, - span: Span::dummy(), - call_path_tree: None, - }, - type_parameters: vec![], - where_clause: vec![], - }; - let impl_trait_item = engines.pe().insert(impl_trait_item); - - let impl_trait = ImplTrait { - impl_type_parameters, - trait_name: abi_encode_trait_name, - trait_type_arguments: vec![], - implementing_for, - items: vec![ImplItem::Fn(impl_trait_item)], - block_span: Span::dummy(), + .map(|x| Self::generate_type(engines, x.type_id)) + .join(", "); + + let type_parameters = if !type_parameters.is_empty() { + format!("<{type_parameters}>") + } else { + type_parameters + }; + + format!("{}{type_parameters}", decl.call_path.suffix.as_str()) + } + TypeInfo::Array(elem_ty, count) => { + format!( + "[{}; {}]", + Self::generate_type(engines, elem_ty.type_id), + count.val() + ) + } + TypeInfo::RawUntypedPtr => "raw_ptr".into(), + TypeInfo::RawUntypedSlice => "raw_slice".into(), + TypeInfo::Alias { name, .. } => name.to_string(), + _ => todo!(), + } + } + + pub(crate) fn generate_contract_entry( + &mut self, + engines: &Engines, + contract_fns: &[DeclRef>], + ) -> Option { + let mut code = String::new(); + + let mut reads = false; + let mut writes = false; + + for r in contract_fns { + let decl = engines.de().get(r.id()); + + match decl.purity { + Purity::Pure => {} + Purity::Reads => reads = true, + Purity::Writes => writes = true, + Purity::ReadsWrites => { + reads = true; + writes = true; + } + } + + let args_types = itertools::intersperse( + decl.parameters + .iter() + .map(|x| Self::generate_type(engines, x.type_argument.type_id)), + ", ".into(), + ) + .collect::(); + + let args_types = if args_types.is_empty() { + "()".into() + } else { + format!("({args_types},)") + }; + + let expanded_args = itertools::intersperse( + decl.parameters + .iter() + .enumerate() + .map(|(i, _)| format!("args.{i}")), + ", ".into(), + ) + .collect::(); + + let return_type = Self::generate_type(engines, decl.return_type.type_id); + + let method_name = decl.name.as_str(); + + if args_types == "()" { + code.push_str(&format!("if method_name == \"{method_name}\" {{ + let result_{method_name}: raw_slice = encode::<{return_type}>(__contract_entry_{method_name}()); + __contract_ret(result_{method_name}.ptr(), result_{method_name}.len::()); + }}\n")); + } else { + code.push_str(&format!("if method_name == \"{method_name}\" {{ + let args = decode_second_param::<{args_types}>(); + let result_{method_name}: raw_slice = encode::<{return_type}>(__contract_entry_{method_name}({expanded_args})); + __contract_ret(result_{method_name}.ptr(), result_{method_name}.len::()); + }}\n")); + } + } + + let att: String = match (reads, writes) { + (true, true) => "#[storage(read, write)]", + (true, false) => "#[storage(read)]", + (false, true) => "#[storage(write)]", + (false, false) => "", + } + .into(); + + let code = format!( + "{att} + pub fn __entry() {{ + let method_name = decode_first_param::(); + __log(method_name); + {code} + }}" + ); + + self.parse_item_fn_to_typed_ast_node(engines, FunctionDeclarationKind::Entry, &code) + } + + pub(crate) fn generate_predicate_entry( + &mut self, + engines: &Engines, + decl: &TyFunctionDecl, + ) -> Option { + let args_types = itertools::intersperse( + decl.parameters + .iter() + .map(|x| Self::generate_type(engines, x.type_argument.type_id)), + ", ".into(), + ) + .collect::(); + + let args_types = if args_types.is_empty() { + "()".into() + } else { + format!("({args_types},)") }; - let impl_trait = engines.pe().insert(impl_trait); - let impl_trait = Declaration::ImplTrait(impl_trait); - let handler = Handler::default(); - TyAstNode::type_check( - &handler, - self.ctx.by_ref(), - AstNode { - content: AstNodeContent::Declaration(impl_trait), - span: Span::dummy(), - }, + let expanded_args = itertools::intersperse( + decl.parameters + .iter() + .enumerate() + .map(|(i, _)| format!("args.{i}")), + ", ".into(), ) - .ok() + .collect::(); + + let code = format!( + "pub fn __entry() -> bool {{ + let args = decode_script_data::<{args_types}>(); + main({expanded_args}) + }}" + ); + self.parse_item_fn_to_typed_ast_node(engines, FunctionDeclarationKind::Entry, &code) } - pub fn auto_impl_abi_encode( + pub(crate) fn generate_script_entry( &mut self, engines: &Engines, - decl: &ty::TyDecl, + decl: &TyFunctionDecl, ) -> Option { - match decl { - TyDecl::StructDecl(_) => self.struct_auto_impl_abi_encode(engines, decl), - TyDecl::EnumDecl(_) => self.enum_auto_impl_abi_encode(engines, decl), - _ => None, - } + let args_types = itertools::intersperse( + decl.parameters + .iter() + .map(|x| Self::generate_type(engines, x.type_argument.type_id)), + ", ".into(), + ) + .collect::(); + + let args_types = if args_types.is_empty() { + "()".into() + } else { + format!("({args_types},)") + }; + + let expanded_args = itertools::intersperse( + decl.parameters + .iter() + .enumerate() + .map(|(i, _)| format!("args.{i}")), + ", ".into(), + ) + .collect::(); + + let return_type = Self::generate_type(engines, decl.return_type.type_id); + + let code = if args_types == "()" { + format!( + "pub fn __entry() -> raw_slice {{ + let result: {return_type} = main(); + encode::<{return_type}>(result) + }}" + ) + } else { + format!( + "pub fn __entry() -> raw_slice {{ + let args = decode_script_data::<{args_types}>(); + let result: {return_type} = main({expanded_args}); + encode::<{return_type}>(result) + }}" + ) + }; + + self.parse_item_fn_to_typed_ast_node(engines, FunctionDeclarationKind::Entry, &code) } } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs index d064e6266ed..65d6a69411a 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -1,17 +1,20 @@ use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Named, Spanned}; +use sway_types::{Ident, Named, Spanned}; use crate::{ - decl_engine::{DeclEngineInsert, DeclRef, ReplaceFunctionImplementingType}, + decl_engine::{ + DeclEngineGet, DeclEngineInsert, DeclRef, ReplaceFunctionImplementingType, Template, + }, language::{ parsed, - ty::{self, TyDecl}, + ty::{self, FunctionDecl, TyDecl}, CallPath, }, namespace::{IsExtendingExistingImpl, IsImplSelf}, semantic_analysis::{ - type_check_context::EnforceTypeArguments, TypeCheckAnalysis, TypeCheckAnalysisContext, - TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext, + type_check_context::EnforceTypeArguments, ConstShadowingMode, GenericShadowingMode, + TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization, + TypeCheckFinalizationContext, }, type_system::*, }; @@ -198,11 +201,11 @@ impl TyDecl { Ok(res) => res, Err(err) => return Ok(ty::TyDecl::ErrorRecovery(span, err)), }; + // if this ImplTrait implements a trait and not an ABI, // we insert its methods into the context - // otherwise, if it implements an ABI, we do not - // insert those since we do not allow calling contract methods - // from contract methods + // otherwise, if it implements an ABI, + // we insert its methods with a prefix let emp_vec = vec![]; let impl_trait_items = if let Ok(ty::TyDecl::TraitDecl { .. }) = ctx.namespace().resolve_call_path( @@ -213,6 +216,31 @@ impl TyDecl { ) { &impl_trait.items } else { + for i in &impl_trait.items { + if let ty::TyTraitItem::Fn(f) = i { + let decl = engines.de().get(f.id()); + let _ = ctx + .namespace + .module_mut() + .current_items_mut() + .insert_symbol( + handler, + Ident::new_no_span(format!( + "__contract_entry_{}", + decl.name.clone() + )), + TyDecl::FunctionDecl(FunctionDecl { + name: decl.name.clone(), + decl_id: *f.id(), + subst_list: Template::default(), + decl_span: f.span(), + }), + ConstShadowingMode::ItemStyle, + GenericShadowingMode::Allow, + ); + } + } + &emp_vec }; diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs index 5d1b8be5bed..743e12c64de 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -56,6 +56,7 @@ impl ty::TyFunctionDecl { visibility, purity, where_clause, + kind, .. } = fn_decl; let mut return_type = fn_decl.return_type.clone(); @@ -157,6 +158,11 @@ impl ty::TyFunctionDecl { purity: *purity, where_clause: where_clause.clone(), is_trait_method_dummy: false, + kind: match kind { + FunctionDeclarationKind::Default => ty::TyFunctionDeclKind::Default, + FunctionDeclarationKind::Entry => ty::TyFunctionDeclKind::Entry, + FunctionDeclarationKind::Test => ty::TyFunctionDeclKind::Test, + }, }; Ok(function_decl) @@ -315,6 +321,7 @@ fn test_function_selector_behavior() { is_contract_call: false, where_clause: vec![], is_trait_method_dummy: false, + kind: ty::TyFunctionDeclKind::Default, }; let selector_text = decl @@ -374,6 +381,7 @@ fn test_function_selector_behavior() { is_contract_call: false, where_clause: vec![], is_trait_method_dummy: false, + kind: ty::TyFunctionDeclKind::Default, }; let selector_text = decl diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs index 82b68a70577..97bfa9d6976 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs @@ -112,6 +112,7 @@ impl ty::TyTraitFn { is_contract_call: matches!(abi_mode, AbiMode::ImplAbiFn(..)), where_clause: vec![], is_trait_method_dummy: true, + kind: ty::TyFunctionDeclKind::Default, } } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs index 46296ef9927..172ae3a4638 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs @@ -86,6 +86,12 @@ impl ty::TyIntrinsicFunctionKind { Intrinsic::JmpMem => { type_check_jmp_mem(handler, ctx, kind, arguments, type_arguments, span) } + Intrinsic::ContractCall => { + type_check_contract_call(handler, ctx, kind, arguments, type_arguments, span) + } + Intrinsic::ContractRet => { + type_check_contract_ret(handler, ctx, kind, arguments, type_arguments, span) + } } } } @@ -137,6 +143,7 @@ fn type_check_not( received: engines.help_out(return_type).to_string(), help_text: "".into(), span, + internal: "8".into(), }, ))), } @@ -1045,6 +1052,7 @@ fn type_check_bitwise_binary_op( received: engines.help_out(return_type).to_string(), help_text: "".into(), span, + internal: "7".into(), }, ))), } @@ -1119,6 +1127,7 @@ fn type_check_shift_binary_op( received: engines.help_out(return_type).to_string(), help_text: "Incorrect argument type".into(), span: lhs.span, + internal: "6".into(), }, ))), } @@ -1409,3 +1418,89 @@ fn type_check_smo( type_engine.insert(engines, TypeInfo::Tuple(vec![]), None), )) } + +/// Signature: `__contract_call()` +/// Description: Calls another contract +/// Constraints: None. +fn type_check_contract_ret( + handler: &Handler, + mut ctx: TypeCheckContext, + _kind: sway_ast::Intrinsic, + arguments: Vec, + _type_arguments: Vec, + _span: Span, +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { + let type_engine = ctx.engines.te(); + let engines = ctx.engines(); + + let arguments: Vec = arguments + .iter() + .map(|x| { + let ctx = ctx + .by_ref() + .with_help_text("") + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + ty::TyExpression::type_check(handler, ctx, x.clone()) + }) + .collect::, _>>()?; + + let t = ctx + .engines + .te() + .insert(ctx.engines, TypeInfo::Tuple(vec![]), None); + + Ok(( + ty::TyIntrinsicFunctionKind { + kind: Intrinsic::ContractRet, + arguments, + type_arguments: vec![], + span: Span::dummy(), + }, + t, + )) +} + +/// Signature: `__contract_call()` +/// Description: Calls another contract +/// Constraints: None. +fn type_check_contract_call( + handler: &Handler, + mut ctx: TypeCheckContext, + kind: sway_ast::Intrinsic, + arguments: Vec, + type_arguments: Vec, + span: Span, +) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { + let type_engine = ctx.engines.te(); + let engines = ctx.engines(); + + if !type_arguments.is_empty() { + return Err(handler.emit_err(CompileError::TypeArgumentsNotAllowed { span })); + } + + let return_type_id = ctx + .engines + .te() + .insert(ctx.engines, TypeInfo::Tuple(vec![]), None); + + // Arguments + let arguments: Vec = arguments + .iter() + .map(|x| { + let ctx = ctx + .by_ref() + .with_help_text("") + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + ty::TyExpression::type_check(handler, ctx, x.clone()) + }) + .collect::, _>>()?; + + let intrinsic_function = ty::TyIntrinsicFunctionKind { + kind, + arguments, + type_arguments: vec![], + span, + }; + + Ok((intrinsic_function, return_type_id)) +} diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 9b941d8787e..77b7b61193c 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -123,13 +123,14 @@ impl ty::TyExpression { let exp = ty::TyExpression { expression: ty::TyExpressionVariant::FunctionApplication { call_path, - contract_call_params: IndexMap::new(), arguments: args_and_names, fn_ref: decl_ref, selector: None, type_binding: None, call_path_typeid: None, deferred_monomorphization: false, + contract_call_params: IndexMap::new(), + contract_caller: None, }, return_type: return_type.type_id, span, @@ -156,6 +157,7 @@ impl ty::TyExpression { suffix: name.clone(), is_absolute: false, }; + if matches!( ctx.namespace() .resolve_call_path( @@ -2421,7 +2423,7 @@ fn check_asm_block_validity( #[cfg(test)] mod tests { use super::*; - use crate::Engines; + use crate::{Engines, ExperimentalFlags}; use sway_error::type_error::TypeError; fn do_type_check( @@ -2429,9 +2431,10 @@ mod tests { engines: &Engines, expr: Expression, type_annotation: TypeId, + experimental: ExperimentalFlags, ) -> Result { let mut namespace = Namespace::init_root(namespace::Module::default()); - let ctx = TypeCheckContext::from_namespace(&mut namespace, engines) + let ctx = TypeCheckContext::from_namespace(&mut namespace, engines, experimental) .with_type_annotation(type_annotation); ty::TyExpression::type_check(handler, ctx, expr) } @@ -2458,6 +2461,9 @@ mod tests { ), None, ), + ExperimentalFlags { + new_encoding: false, + }, ) } @@ -2602,6 +2608,9 @@ mod tests { ), None, ), + ExperimentalFlags { + new_encoding: false, + }, ); let (errors, warnings) = handler.consume(); assert!(comp_res.is_ok()); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs index a64da335a3e..b985dfd854c 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/function_application.rs @@ -72,6 +72,7 @@ pub(crate) fn instantiate_function_application( function_decl.name.as_str(), &call_path_binding.span(), )?; + function_decl.replace_decls(&decl_mapping, handler, &mut ctx)?; let return_type = function_decl.return_type.clone(); let new_decl_ref = decl_engine @@ -81,13 +82,14 @@ pub(crate) fn instantiate_function_application( let exp = ty::TyExpression { expression: ty::TyExpressionVariant::FunctionApplication { call_path: call_path_binding.inner.clone(), - contract_call_params: IndexMap::new(), arguments: typed_arguments_with_names, fn_ref: new_decl_ref, selector: None, type_binding: Some(call_path_binding.strip_inner()), call_path_typeid: None, deferred_monomorphization: false, + contract_call_params: IndexMap::new(), + contract_caller: None, }, return_type: return_type.type_id, span, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs index bdd3679c869..fd9cb084665 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs @@ -80,6 +80,7 @@ pub(crate) fn instantiate_if_expression( help_text: "The two branches of an if expression must return the same type." .to_string(), span: span.clone(), + internal: "".into(), })); } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index a6d6fd62639..654f1df0837 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs @@ -5,7 +5,7 @@ use crate::{ }, language::{ parsed::*, - ty::{self, TyDecl}, + ty::{self, TyDecl, TyExpression}, *, }, namespace::TryInsertingTraitImplOnFailure, @@ -135,6 +135,7 @@ pub(crate) fn type_check_method_application( } // generate the map of the contract call params + let mut untyped_contract_call_params_map = std::collections::HashMap::new(); let mut contract_call_params_map = IndexMap::new(); if method.is_contract_call { for param_name in &[ @@ -160,6 +161,8 @@ pub(crate) fn type_check_method_application( constants::CONTRACT_CALL_GAS_PARAMETER_NAME | constants::CONTRACT_CALL_COINS_PARAMETER_NAME | constants::CONTRACT_CALL_ASSET_ID_PARAMETER_NAME => { + untyped_contract_call_params_map + .insert(param.name.to_string(), param.value.clone()); let type_annotation = type_engine.insert( engines, if param.name.span().as_str() @@ -388,6 +391,7 @@ pub(crate) fn type_check_method_application( is_method_call_syntax_used, )?; + let old_arguments = arguments; let arguments = method .parameters .iter() @@ -395,15 +399,152 @@ pub(crate) fn type_check_method_application( .zip(args_buf.iter().cloned()) .collect::>(); + if ctx.experimental.new_encoding && method.is_contract_call { + fn call_contract_call( + ctx: &mut TypeCheckContext, + original_span: Span, + return_type: TypeId, + method_name_expr: Expression, + _caller: Expression, + arguments: Vec, + typed_argumens: Vec, + coins_expr: Expression, + asset_id_expr: Expression, + gas_expr: Expression, + ) -> Expression { + let tuple_args_type_id = ctx.engines.te().insert( + ctx.engines, + TypeInfo::Tuple( + typed_argumens + .iter() + .map(|&type_id| TypeArgument { + type_id, + initial_type_id: type_id, + span: Span::dummy(), + call_path_tree: None, + }) + .collect(), + ), + None, + ); + Expression { + kind: ExpressionKind::FunctionApplication(Box::new( + FunctionApplicationExpression { + call_path_binding: TypeBinding { + inner: CallPath { + prefixes: vec![], + suffix: Ident::new_no_span("contract_call".into()), + is_absolute: false, + }, + type_arguments: TypeArgs::Regular(vec![ + TypeArgument { + type_id: return_type, + initial_type_id: return_type, + span: Span::dummy(), + call_path_tree: None, + }, + TypeArgument { + type_id: tuple_args_type_id, + initial_type_id: tuple_args_type_id, + span: Span::dummy(), + call_path_tree: None, + }, + ]), + span: Span::dummy(), + }, + arguments: vec![ + Expression { + kind: ExpressionKind::Literal(Literal::B256([0u8; 32])), + span: Span::dummy(), + }, + method_name_expr, + as_tuple(arguments), + coins_expr, + asset_id_expr, + gas_expr, + ], + }, + )), + span: original_span, + } + } + + fn string_slice_literal(ident: &BaseIdent) -> Expression { + Expression { + kind: ExpressionKind::Literal(Literal::String(ident.span())), + span: ident.span(), + } + } + + fn as_tuple(elements: Vec) -> Expression { + Expression { + kind: ExpressionKind::Tuple(elements), + span: Span::dummy(), + } + } + + let gas_expr = untyped_contract_call_params_map + .remove(constants::CONTRACT_CALL_GAS_PARAMETER_NAME) + .unwrap_or_else(|| Expression { + kind: ExpressionKind::Literal(Literal::U64(u64::MAX)), + span: Span::dummy(), + }); + let coins_expr = untyped_contract_call_params_map + .remove(constants::CONTRACT_CALL_COINS_PARAMETER_NAME) + .unwrap_or_else(|| Expression { + kind: ExpressionKind::Literal(Literal::U64(0)), + span: Span::dummy(), + }); + let asset_id_expr = untyped_contract_call_params_map + .remove(constants::CONTRACT_CALL_ASSET_ID_PARAMETER_NAME) + .unwrap_or_else(|| Expression { + kind: ExpressionKind::Literal(Literal::B256([0u8; 32])), + span: Span::dummy(), + }); + + let contract_call = call_contract_call( + &mut ctx, + span, + method.return_type.type_id, + string_slice_literal(&method.name), + old_arguments.first().cloned().unwrap(), + old_arguments.into_iter().skip(1).collect(), + arguments.iter().map(|x| x.1.return_type).collect(), + coins_expr, + asset_id_expr, + gas_expr, + ); + let mut expr = TyExpression::type_check(handler, ctx.by_ref(), contract_call)?; + + // We need to "fix" contract_id here because it was created with zero + // given that we only have it as TyExpression, therefore can only use it after we type_check + // `expr`` + match &mut expr.expression { + ty::TyExpressionVariant::FunctionApplication { + arguments, + contract_caller, + .. + } => { + let selector = selector.unwrap(); + arguments[0].1 = (*selector.contract_address).clone(); + *contract_caller = Some(selector.contract_caller); + } + _ => unreachable!(), + } + + return Ok(expr); + } + let mut fn_app = ty::TyExpressionVariant::FunctionApplication { call_path: call_path.clone(), - contract_call_params: contract_call_params_map, arguments, fn_ref: original_decl_ref, selector, type_binding: Some(method_name_binding.strip_inner()), call_path_typeid: Some(call_path_typeid), deferred_monomorphization: ctx.defer_monomorphization(), + contract_call_params: contract_call_params_map, + contract_caller: None, }; let mut exp = ty::TyExpression { @@ -621,6 +762,7 @@ pub(crate) fn monomorphize_method_application( type_binding.as_mut().unwrap().type_arguments.to_vec_mut(), )?; let mut method = (*decl_engine.get_function(fn_ref)).clone(); + method.is_trait_method_dummy = false; // unify the types of the arguments with the types of the parameters from the function declaration *arguments = diff --git a/sway-core/src/semantic_analysis/cei_pattern_analysis.rs b/sway-core/src/semantic_analysis/cei_pattern_analysis.rs index 61e6fb5fc5e..52d1b7f0f0d 100644 --- a/sway-core/src/semantic_analysis/cei_pattern_analysis.rs +++ b/sway-core/src/semantic_analysis/cei_pattern_analysis.rs @@ -609,8 +609,9 @@ fn effects_of_intrinsic(intr: &sway_ast::Intrinsic) -> HashSet { StateLoadWord | StateLoadQuad => HashSet::from([Effect::StorageRead]), Smo => HashSet::from([Effect::OutputMessage]), Revert | JmpMem | IsReferenceType | IsStrArray | SizeOfType | SizeOfVal | SizeOfStr - | AssertIsStrArray | ToStrArray | Eq | Gt | Lt | Gtf | AddrOf | Log | Add | Sub | Mul - | Div | And | Or | Xor | Mod | Rsh | Lsh | PtrAdd | PtrSub | Not => HashSet::new(), + | ContractCall | ContractRet | AssertIsStrArray | ToStrArray | Eq | Gt | Lt | Gtf + | AddrOf | Log | Add | Sub | Mul | Div | And | Or | Xor | Mod | Rsh | Lsh | PtrAdd + | PtrSub | Not => HashSet::new(), } } diff --git a/sway-core/src/semantic_analysis/module.rs b/sway-core/src/semantic_analysis/module.rs index af492e563ee..8c51b9b7090 100644 --- a/sway-core/src/semantic_analysis/module.rs +++ b/sway-core/src/semantic_analysis/module.rs @@ -23,7 +23,7 @@ use crate::{ Engines, TypeInfo, }; -use super::declaration::auto_impl::AutoImplAbiEncodeContext; +use super::declaration::auto_impl::{self, AutoImplAbiEncodeContext}; #[derive(Clone, Debug)] pub struct ModuleDepGraphEdge(); @@ -220,6 +220,8 @@ impl ty::TyModule { pub fn type_check( handler: &Handler, mut ctx: TypeCheckContext, + engines: &Engines, + kind: TreeType, parsed: &ParseModule, module_eval_order: ModuleEvaluationOrder, ) -> Result { @@ -228,7 +230,6 @@ impl ty::TyModule { tree, attributes, span, - hash: _, .. } = parsed; @@ -242,29 +243,79 @@ impl ty::TyModule { .unwrap(); Ok(( name.clone(), - ty::TySubmodule::type_check(handler, ctx.by_ref(), name.clone(), submodule)?, + ty::TySubmodule::type_check( + handler, + ctx.by_ref(), + engines, + name.clone(), + kind, + submodule, + )?, )) }) .collect::, _>>(); // TODO: Ordering should be solved across all modules prior to the beginning of type-check. - let ordered_nodes_res = node_dependencies::order_ast_nodes_by_dependency( + let ordered_nodes = node_dependencies::order_ast_nodes_by_dependency( handler, ctx.engines(), tree.root_nodes.clone(), - ); - - let typed_nodes_res = ordered_nodes_res - .and_then(|ordered_nodes| Self::type_check_nodes(handler, ctx.by_ref(), ordered_nodes)); - - submodules_res.and_then(|submodules| { - typed_nodes_res.map(|all_nodes| Self { - span: span.clone(), - submodules, - namespace: ctx.namespace().clone(), - all_nodes, - attributes: attributes.clone(), - }) + )?; + + let mut all_nodes = Self::type_check_nodes(handler, ctx.by_ref(), ordered_nodes)?; + let submodules = submodules_res?; + + if ctx.experimental.new_encoding { + let main_decl = all_nodes.iter_mut().find_map(|x| match &mut x.content { + ty::TyAstNodeContent::Declaration(ty::TyDecl::FunctionDecl(decl)) => { + (decl.name.as_str() == "main").then(|| engines.de().get(&decl.decl_id)) + } + _ => None, + }); + + match (&kind, main_decl.is_some()) { + (TreeType::Predicate, true) => { + let mut fn_generator = + auto_impl::AutoImplAbiEncodeContext::new(&mut ctx).unwrap(); + let node = fn_generator + .generate_predicate_entry(engines, main_decl.as_ref().unwrap()) + .unwrap(); + all_nodes.push(node) + } + (TreeType::Script, true) => { + let mut fn_generator = + auto_impl::AutoImplAbiEncodeContext::new(&mut ctx).unwrap(); + let node = fn_generator + .generate_script_entry(engines, main_decl.as_ref().unwrap()) + .unwrap(); + all_nodes.push(node) + } + (TreeType::Contract, _) => { + // collect all contract methods + let contract_fns = submodules + .iter() + .flat_map(|x| x.1.module.submodules_recursive()) + .flat_map(|x| x.1.module.contract_fns(engines)) + .chain(all_nodes.iter().flat_map(|x| x.contract_fns(engines))) + .collect::>(); + + let mut fn_generator = + auto_impl::AutoImplAbiEncodeContext::new(&mut ctx).unwrap(); + let node = fn_generator + .generate_contract_entry(engines, &contract_fns) + .unwrap(); + all_nodes.push(node) + } + _ => {} + } + } + + Ok(Self { + span: span.clone(), + submodules, + namespace: ctx.namespace.clone(), + all_nodes, + attributes: attributes.clone(), }) } @@ -322,7 +373,7 @@ impl ty::TyModule { let mut typed_nodes = vec![]; for node in nodes { - let auto_impl_abiencode = match &node.content { + let auto_impl_encoding_traits = match &node.content { AstNodeContent::Declaration(Declaration::StructDeclaration(decl_id)) => { let decl = ctx.engines().pe().get_struct(decl_id); all_abiencode_impls.get(&decl.name).is_none() @@ -338,18 +389,28 @@ impl ty::TyModule { continue; }; - match (auto_impl_abiencode, AutoImplAbiEncodeContext::new(&mut ctx)) { - (true, Some(mut ctx)) => match &node.content { - TyAstNodeContent::Declaration(decl @ TyDecl::StructDecl(_)) - | TyAstNodeContent::Declaration(decl @ TyDecl::EnumDecl(_)) => { - ctx.auto_impl_abi_encode(engines, decl) + if ctx.experimental.new_encoding { + let mut generated = vec![]; + if let (true, Some(mut ctx)) = ( + auto_impl_encoding_traits, + AutoImplAbiEncodeContext::new(&mut ctx), + ) { + match &node.content { + TyAstNodeContent::Declaration(decl @ TyDecl::StructDecl(_)) + | TyAstNodeContent::Declaration(decl @ TyDecl::EnumDecl(_)) => { + let (a, b) = ctx.generate(engines, decl); + generated.extend(a); + generated.extend(b); + } + _ => {} } - _ => None, - }, - _ => None, - }; + }; - typed_nodes.push(node); + typed_nodes.push(node); + typed_nodes.extend(generated); + } else { + typed_nodes.push(node); + } } Ok(typed_nodes) @@ -396,7 +457,9 @@ impl ty::TySubmodule { pub fn type_check( handler: &Handler, parent_ctx: TypeCheckContext, + engines: &Engines, mod_name: ModName, + kind: TreeType, submodule: &ParseSubmodule, ) -> Result { let ParseSubmodule { @@ -407,8 +470,14 @@ impl ty::TySubmodule { let modules_dep_graph = ty::TyModule::analyze(handler, module)?; let module_eval_order = modules_dep_graph.compute_order(handler)?; parent_ctx.enter_submodule(mod_name, *visibility, module.span.clone(), |submod_ctx| { - let module_res = - ty::TyModule::type_check(handler, submod_ctx, module, module_eval_order); + let module_res = ty::TyModule::type_check( + handler, + submod_ctx, + engines, + kind, + module, + module_eval_order, + ); module_res.map(|module| ty::TySubmodule { module, mod_name_span: mod_name_span.clone(), diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 8cfbdfe10d3..d0d03f5f511 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -89,17 +89,23 @@ impl Module { engines: &Engines, name: Option, contract_id_value: String, + experimental: crate::ExperimentalFlags, ) -> Result> { let handler = <_>::default(); - Module::default_with_contract_id_inner(&handler, engines, name, contract_id_value).map_err( - |_| { - let (errors, warnings) = handler.consume(); - assert!(warnings.is_empty()); - - // Invariant: `.value == None` => `!errors.is_empty()`. - vec1::Vec1::try_from_vec(errors).unwrap() - }, + Module::default_with_contract_id_inner( + &handler, + engines, + name, + contract_id_value, + experimental, ) + .map_err(|_| { + let (errors, warnings) = handler.consume(); + assert!(warnings.is_empty()); + + // Invariant: `.value == None` => `!errors.is_empty()`. + vec1::Vec1::try_from_vec(errors).unwrap() + }) } fn default_with_contract_id_inner( @@ -107,6 +113,7 @@ impl Module { engines: &Engines, ns_name: Option, contract_id_value: String, + experimental: crate::ExperimentalFlags, ) -> Result { // it would be nice to one day maintain a span from the manifest file, but // we don't keep that around so we just use the span from the generated const decl instead. @@ -160,7 +167,7 @@ impl Module { ns.root.module.name = ns_name; ns.root.module.is_external = true; ns.root.module.visibility = Visibility::Public; - let type_check_ctx = TypeCheckContext::from_namespace(&mut ns, engines); + let type_check_ctx = TypeCheckContext::from_namespace(&mut ns, engines, experimental); let typed_node = ty::TyAstNode::type_check(handler, type_check_ctx, ast_node).unwrap(); // get the decl out of the typed node: // we know as an invariant this must be a const decl, as we hardcoded a const decl in diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index 331ef52afbb..a6312707c11 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -1000,6 +1000,35 @@ impl TraitMap { try_inserting_trait_impl_on_failure: TryInsertingTraitImplOnFailure, ) -> Result<(), ErrorEmitted> { let type_engine = engines.te(); + + // If the type is generic/placeholder, its definition needs to contains all + // constraints + match &*type_engine.get(type_id) { + TypeInfo::UnknownGeneric { + trait_constraints, .. + } => { + let all = constraints.iter().all(|required| { + trait_constraints + .iter() + .any(|constraint| constraint.eq(required, engines)) + }); + if all { + return Ok(()); + } + } + TypeInfo::Placeholder(p) => { + let all = constraints.iter().all(|required| { + p.trait_constraints + .iter() + .any(|constraint| constraint.eq(required, engines)) + }); + if all { + return Ok(()); + } + } + _ => {} + } + let _decl_engine = engines.de(); let unify_check = UnifyCheck::non_dynamic_equality(engines); @@ -1094,6 +1123,7 @@ impl TraitMap { { type_arguments_string = format!("<{}>", engines.help_out(type_arguments)); } + // TODO: use a better span handler.emit_err(CompileError::TraitConstraintNotSatisfied { ty: engines.help_out(type_id).to_string(), diff --git a/sway-core/src/semantic_analysis/program.rs b/sway-core/src/semantic_analysis/program.rs index 4c77de9fa12..4244abc3eda 100644 --- a/sway-core/src/semantic_analysis/program.rs +++ b/sway-core/src/semantic_analysis/program.rs @@ -31,29 +31,48 @@ impl TyProgram { package_name: &str, build_config: Option<&BuildConfig>, ) -> Result { + let experimental = build_config.map(|x| x.experimental).unwrap_or_default(); + let mut namespace = Namespace::init_root(initial_namespace); - let ctx = TypeCheckContext::from_namespace(&mut namespace, engines) - .with_kind(parsed.kind.clone()) - .with_experimental_flags(build_config.map(|x| x.experimental)); + let mut ctx = TypeCheckContext::from_root(&mut namespace, engines, experimental) + .with_kind(parsed.kind); let ParseProgram { root, kind } = parsed; // Analyze the dependency order for the submodules. let modules_dep_graph = ty::TyModule::analyze(handler, root)?; - let module_eval_order = modules_dep_graph.compute_order(handler)?; + let module_eval_order: Vec = + modules_dep_graph.compute_order(handler)?; - ty::TyModule::type_check(handler, ctx, root, module_eval_order).and_then(|root| { - let res = Self::validate_root(handler, engines, &root, kind.clone(), package_name); - res.map(|(kind, declarations, configurables)| Self { - kind, - root, - declarations, - configurables, - storage_slots: vec![], - logged_types: vec![], - messages_types: vec![], - }) - }) + let root = ty::TyModule::type_check( + handler, + ctx.by_ref(), + engines, + parsed.kind, + root, + module_eval_order, + )?; + + let (kind, declarations, configurables) = Self::validate_root( + handler, + engines, + &root, + *kind, + package_name, + ctx.experimental, + )?; + + let program = TyProgram { + kind, + root, + declarations, + configurables, + storage_slots: vec![], + logged_types: vec![], + messages_types: vec![], + }; + + Ok(program) } pub(crate) fn get_typed_program_with_initialized_storage_slots( diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index 8ec36b02494..20a0f2a29a3 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -104,7 +104,11 @@ pub struct TypeCheckContext<'a> { impl<'a> TypeCheckContext<'a> { /// Initialize a type-checking context with a namespace. - pub fn from_namespace(namespace: &'a mut Namespace, engines: &'a Engines) -> Self { + pub fn from_namespace( + namespace: &'a mut Namespace, + engines: &'a Engines, + experimental: ExperimentalFlags, + ) -> Self { Self { namespace, engines, @@ -122,7 +126,49 @@ impl<'a> TypeCheckContext<'a> { disallow_functions: false, defer_monomorphization: false, storage_declaration: false, - experimental: ExperimentalFlags::default(), + experimental, + } + } + + /// Initialize a context at the top-level of a module with its namespace. + /// + /// Initializes with: + /// + /// - type_annotation: unknown + /// - mode: NoneAbi + /// - help_text: "" + /// - purity: Pure + pub fn from_root( + root_namespace: &'a mut Namespace, + engines: &'a Engines, + experimental: ExperimentalFlags, + ) -> Self { + Self::from_module_namespace(root_namespace, engines, experimental) + } + + fn from_module_namespace( + namespace: &'a mut Namespace, + engines: &'a Engines, + experimental: ExperimentalFlags, + ) -> Self { + Self { + namespace, + engines, + type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), + function_type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), + unify_generic: false, + self_type: None, + type_subst: TypeSubstMap::new(), + help_text: "", + abi_mode: AbiMode::NonAbi, + const_shadowing_mode: ConstShadowingMode::ItemStyle, + generic_shadowing_mode: GenericShadowingMode::Disallow, + purity: Purity::default(), + kind: TreeType::Contract, + disallow_functions: false, + defer_monomorphization: false, + storage_declaration: false, + experimental, } } @@ -147,7 +193,7 @@ impl<'a> TypeCheckContext<'a> { generic_shadowing_mode: self.generic_shadowing_mode, help_text: self.help_text, purity: self.purity, - kind: self.kind.clone(), + kind: self.kind, engines: self.engines, disallow_functions: self.disallow_functions, defer_monomorphization: self.defer_monomorphization, @@ -195,13 +241,15 @@ impl<'a> TypeCheckContext<'a> { module_span: Span, with_submod_ctx: impl FnOnce(TypeCheckContext) -> T, ) -> T { + let experimental = self.experimental; + // We're checking a submodule, so no need to pass through anything other than the // namespace and the engines. let engines = self.engines; let mut submod_ns = self .namespace_mut() .enter_submodule(mod_name, visibility, module_span); - let submod_ctx = TypeCheckContext::from_namespace(&mut submod_ns, engines); + let submod_ctx = TypeCheckContext::from_namespace(&mut submod_ns, engines, experimental); with_submod_ctx(submod_ctx) } @@ -375,7 +423,7 @@ impl<'a> TypeCheckContext<'a> { #[allow(dead_code)] pub(crate) fn kind(&self) -> TreeType { - self.kind.clone() + self.kind } pub(crate) fn functions_disallowed(&self) -> bool { @@ -1614,17 +1662,6 @@ impl<'a> TypeCheckContext<'a> { .insert_for_type(engines, type_id); } - pub(crate) fn with_experimental_flags(self, experimental: Option) -> Self { - let Some(experimental) = experimental else { - return self; - }; - - Self { - experimental, - ..self - } - } - pub fn check_type_impls_traits( &mut self, type_id: TypeId, diff --git a/sway-core/src/transform/to_parsed_lang/context.rs b/sway-core/src/transform/to_parsed_lang/context.rs index bb5bcd32f1d..3ad43f1c991 100644 --- a/sway-core/src/transform/to_parsed_lang/context.rs +++ b/sway-core/src/transform/to_parsed_lang/context.rs @@ -70,7 +70,7 @@ impl Context { /// Returns the program type. pub fn program_type(&self) -> Option { - self.program_type.clone() + self.program_type } /// Updates the value of `program_type`. diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index 1486d44550b..4404585980e 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -52,7 +52,7 @@ pub fn convert_parse_tree( module: Module, ) -> Result<(TreeType, ParseTree), ErrorEmitted> { let tree_type = convert_module_kind(&module.kind); - context.set_program_type(tree_type.clone()); + context.set_program_type(tree_type); let tree = module_to_sway_parse_tree(context, handler, engines, module)?; Ok((tree_type, tree)) } @@ -78,8 +78,15 @@ pub fn module_to_sway_parse_tree( let mut root_nodes: Vec = vec![]; let mut prev_item: Option> = None; for item in module.items { - let ast_nodes = - item_to_ast_nodes(context, handler, engines, item.clone(), true, prev_item)?; + let ast_nodes = item_to_ast_nodes( + context, + handler, + engines, + item.clone(), + true, + prev_item, + None, + )?; root_nodes.extend(ast_nodes); prev_item = Some(item); } @@ -98,13 +105,14 @@ fn ast_node_is_test_fn(engines: &Engines, node: &AstNode) -> bool { false } -fn item_to_ast_nodes( +pub fn item_to_ast_nodes( context: &mut Context, handler: &Handler, engines: &Engines, item: Item, is_root: bool, prev_item: Option>, + override_kind: Option, ) -> Result, ErrorEmitted> { let attributes = item_attrs_to_map(context, handler, &item.attribute_list)?; if !cfg_eval(context, handler, &attributes, context.experimental)? { @@ -172,7 +180,14 @@ fn item_to_ast_nodes( )), ItemKind::Fn(item_fn) => { let function_declaration_decl_id = item_fn_to_function_declaration( - context, handler, engines, item_fn, attributes, None, None, + context, + handler, + engines, + item_fn, + attributes, + None, + None, + override_kind, )?; let function_declaration = engines.pe().get_function(&function_declaration_decl_id); error_if_self_param_is_not_allowed( @@ -472,7 +487,8 @@ fn item_enum_to_enum_declaration( Ok(enum_declaration_id) } -fn item_fn_to_function_declaration( +#[allow(clippy::too_many_arguments)] +pub fn item_fn_to_function_declaration( context: &mut Context, handler: &Handler, engines: &Engines, @@ -480,6 +496,7 @@ fn item_fn_to_function_declaration( attributes: AttributesMap, parent_generic_params_opt: Option, parent_where_clause_opt: Option, + override_kind: Option, ) -> Result, ErrorEmitted> { let span = item_fn.span(); let return_type = match item_fn.fn_signature.return_type_opt { @@ -498,6 +515,17 @@ fn item_fn_to_function_declaration( } } }; + + let kind = match ( + context.experimental.new_encoding, + item_fn.fn_signature.name.as_str() == "main", + ) { + (false, true) => FunctionDeclarationKind::Entry, + _ => FunctionDeclarationKind::Default, + }; + + let kind = override_kind.unwrap_or(kind); + let fn_decl = FunctionDeclaration { purity: get_attributed_purity(context, handler, &attributes)?, attributes, @@ -529,6 +557,7 @@ fn item_fn_to_function_declaration( }) .transpose()? .unwrap_or(vec![]), + kind, }; let decl_id = engines.pe().insert(fn_decl); Ok(decl_id) @@ -646,6 +675,7 @@ fn item_trait_to_trait_declaration( attributes, item_trait.generics.clone(), item_trait.where_clause_opt.clone(), + None, )?)) }) .filter_map_ok(|fn_decl| fn_decl) @@ -669,7 +699,7 @@ fn item_trait_to_trait_declaration( Ok(trait_decl_id) } -fn item_impl_to_declaration( +pub fn item_impl_to_declaration( context: &mut Context, handler: &Handler, engines: &Engines, @@ -695,6 +725,7 @@ fn item_impl_to_declaration( attributes, item_impl.generic_params_opt.clone(), item_impl.where_clause_opt.clone(), + None, ) .map(ImplItem::Fn), sway_ast::ItemImplItem::Const(const_item) => item_const_to_constant_declaration( @@ -856,6 +887,7 @@ fn item_abi_to_abi_declaration( attributes, None, None, + None, )?; let function_declaration = engines.pe().get_function(&function_declaration_id); error_if_self_param_is_not_allowed( @@ -2477,7 +2509,7 @@ fn statement_to_ast_nodes( statement_let_to_ast_nodes(context, handler, engines, statement_let)? } Statement::Item(item) => { - let nodes = item_to_ast_nodes(context, handler, engines, item, false, None)?; + let nodes = item_to_ast_nodes(context, handler, engines, item, false, None, None)?; nodes.iter().try_fold((), |res, node| { if ast_node_is_test_fn(engines, node) { let span = node.span.clone(); diff --git a/sway-core/src/type_system/ast_elements/type_parameter.rs b/sway-core/src/type_system/ast_elements/type_parameter.rs index b27dc766254..25ef5f01ee0 100644 --- a/sway-core/src/type_system/ast_elements/type_parameter.rs +++ b/sway-core/src/type_system/ast_elements/type_parameter.rs @@ -127,7 +127,11 @@ impl DebugWithEngines for TypeParameter { impl fmt::Debug for TypeParameter { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {:?}", self.name_ident, self.type_id) + let _ = write!(f, "{}: {:?}", self.name_ident, self.type_id); + for c in self.trait_constraints.iter() { + let _ = write!(f, "+ {:?}", c.trait_name); + } + write!(f, "") } } diff --git a/sway-core/src/type_system/engine.rs b/sway-core/src/type_system/engine.rs index 0f5a382f580..c6f316e3a78 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -229,15 +229,21 @@ impl TypeEngine { received: engines.help_out(received).to_string(), help_text: help_text.to_string(), span: span.clone(), + internal: format!( + "expected:[{:?}]; received:[{:?}]", + engines.help_out(expected), + engines.help_out(received), + ), })); } } return; } + let h = Handler::default(); let unifier = Unifier::new(engines, help_text, unify_kind); - unifier.unify(handler, received, expected, span); + match err_override { Some(err_override) if h.has_errors() => { handler.emit_err(err_override); diff --git a/sway-core/src/type_system/unify/unifier.rs b/sway-core/src/type_system/unify/unifier.rs index 48d149d3b33..73ab0c53d44 100644 --- a/sway-core/src/type_system/unify/unifier.rs +++ b/sway-core/src/type_system/unify/unifier.rs @@ -279,6 +279,7 @@ impl<'a> Unifier<'a> { received, help_text: self.help_text.clone(), span: span.clone(), + internal: "4".into(), } .into(), ); @@ -307,6 +308,7 @@ impl<'a> Unifier<'a> { received, help_text: self.help_text.clone(), span: span.clone(), + internal: "3".into(), } .into(), ); @@ -350,6 +352,7 @@ impl<'a> Unifier<'a> { received, help_text: self.help_text.clone(), span: span.clone(), + internal: "2".into(), } .into(), ); @@ -380,6 +383,8 @@ impl<'a> Unifier<'a> { self.unify(handler, rtp.type_id, etp.type_id, span); }); } else { + dbg!(rn == en, rvs.len() == evs.len(), rtps.len() == etps.len()); + let internal = format!("[{:?}] versus [{:?}]", received, expected); let (received, expected) = self.assign_args(received, expected); handler.emit_err( TypeError::MismatchedType { @@ -387,6 +392,7 @@ impl<'a> Unifier<'a> { received, help_text: self.help_text.clone(), span: span.clone(), + internal, } .into(), ); @@ -425,6 +431,7 @@ impl<'a> Unifier<'a> { received, help_text: self.help_text.clone(), span: span.clone(), + internal: "1".into(), } .into(), ); diff --git a/sway-core/src/type_system/unify/unify_check.rs b/sway-core/src/type_system/unify/unify_check.rs index bc07e738244..04e8912366f 100644 --- a/sway-core/src/type_system/unify/unify_check.rs +++ b/sway-core/src/type_system/unify/unify_check.rs @@ -208,6 +208,7 @@ impl<'a> UnifyCheck<'a> { if left == right { return true; } + let left_info = self.engines.te().get(left); let right_info = self.engines.te().get(right); diff --git a/sway-error/src/type_error.rs b/sway-error/src/type_error.rs index c3ed46b0750..a4d7d3fd389 100644 --- a/sway-error/src/type_error.rs +++ b/sway-error/src/type_error.rs @@ -15,6 +15,7 @@ pub enum TypeError { received: String, help_text: String, span: Span, + internal: String, }, #[error("This type is not known. Try annotating it with a type annotation.")] UnknownType { span: Span }, diff --git a/sway-ir/src/analysis/memory_utils.rs b/sway-ir/src/analysis/memory_utils.rs index dfc8829bf95..0b3a620e3f5 100644 --- a/sway-ir/src/analysis/memory_utils.rs +++ b/sway-ir/src/analysis/memory_utils.rs @@ -210,6 +210,7 @@ pub fn get_loaded_ptr_values(context: &Context, val: Value) -> Vec { InstOp::FuelVm(FuelVmInstruction::WideModularOp { arg1, arg2, arg3, .. }) => vec![*arg1, *arg2, *arg3], + InstOp::FuelVm(FuelVmInstruction::Retd { ptr, .. }) => vec![*ptr], } } @@ -264,6 +265,7 @@ pub fn get_stored_ptr_values(context: &Context, val: Value) -> Vec { | FuelVmInstruction::WideBinaryOp { result, .. } | FuelVmInstruction::WideModularOp { result, .. } => vec![*result], FuelVmInstruction::WideCmpOp { .. } => vec![], + _ => vec![], }, } } diff --git a/sway-ir/src/context.rs b/sway-ir/src/context.rs index 6d4dda4cc28..4cbdeb50c1e 100644 --- a/sway-ir/src/context.rs +++ b/sway-ir/src/context.rs @@ -39,7 +39,7 @@ pub struct Context<'eng> { pub experimental: ExperimentalFlags, } -#[derive(Default)] +#[derive(Copy, Clone, Default)] pub struct ExperimentalFlags { pub new_encoding: bool, } diff --git a/sway-ir/src/instruction.rs b/sway-ir/src/instruction.rs index de9b316b858..4f4f33ed11d 100644 --- a/sway-ir/src/instruction.rs +++ b/sway-ir/src/instruction.rs @@ -75,7 +75,7 @@ pub enum InstOp { /// A contract call with a list of arguments ContractCall { return_type: Type, - name: String, + name: Option, params: Value, coins: Value, asset_id: Value, @@ -195,6 +195,10 @@ pub enum FuelVmInstruction { arg2: Value, }, JmpMem, + Retd { + ptr: Value, + len: Value, + }, } /// Comparison operations. @@ -277,6 +281,7 @@ impl InstOp { InstOp::FuelVm(FuelVmInstruction::Log { .. }) => Some(Type::get_unit(context)), InstOp::FuelVm(FuelVmInstruction::ReadRegister(_)) => Some(Type::get_uint64(context)), InstOp::FuelVm(FuelVmInstruction::Smo { .. }) => Some(Type::get_unit(context)), + InstOp::FuelVm(FuelVmInstruction::Retd { .. }) => None, // Load needs to strip the pointer from the source type. InstOp::Load(ptr_val) => match &context.values[ptr_val.0].value { @@ -446,6 +451,9 @@ impl InstOp { arg3, .. } => vec![*result, *arg1, *arg2, *arg3], + FuelVmInstruction::Retd { ptr, len } => { + vec![*ptr, *len] + } }, } } @@ -617,6 +625,10 @@ impl InstOp { replace(arg2); replace(arg3); } + FuelVmInstruction::Retd { ptr, len } => { + replace(ptr); + replace(len); + } }, } } @@ -632,7 +644,9 @@ impl InstOp { | InstOp::FuelVm(FuelVmInstruction::StateLoadQuadWord { .. }) | InstOp::FuelVm(FuelVmInstruction::StateStoreQuadWord { .. }) | InstOp::FuelVm(FuelVmInstruction::StateStoreWord { .. }) - | InstOp::FuelVm(FuelVmInstruction::Revert(..) | FuelVmInstruction::JmpMem) + | InstOp::FuelVm(FuelVmInstruction::Revert(..)) + | InstOp::FuelVm(FuelVmInstruction::JmpMem) + | InstOp::FuelVm(FuelVmInstruction::Retd { .. }) | InstOp::MemCopyBytes { .. } | InstOp::MemCopyVal { .. } | InstOp::Store { .. } @@ -950,7 +964,7 @@ impl<'a, 'eng> InstructionInserter<'a, 'eng> { pub fn contract_call( self, return_type: Type, - name: String, + name: Option, params: Value, coins: Value, // amount of coins to forward asset_id: Value, // b256 asset ID of the coint being forwarded @@ -1063,6 +1077,10 @@ impl<'a, 'eng> InstructionInserter<'a, 'eng> { insert_instruction!(self, InstOp::Ret(value, ty)) } + pub fn retd(self, ptr: Value, len: Value) -> Value { + insert_instruction!(self, InstOp::FuelVm(FuelVmInstruction::Retd { ptr, len })) + } + pub fn revert(self, value: Value) -> Value { let revert_val = Value::new_instruction( self.context, diff --git a/sway-ir/src/irtype.rs b/sway-ir/src/irtype.rs index 94872aece75..f65ccf18736 100644 --- a/sway-ir/src/irtype.rs +++ b/sway-ir/src/irtype.rs @@ -147,7 +147,7 @@ impl Type { } /// Get slice type - pub fn get_slice(context: &mut Context) -> Type { + pub fn get_slice(context: &Context) -> Type { Self::get_type(context, &TypeContent::Slice).expect("create_basic_types not called") } @@ -742,9 +742,9 @@ mod tests { /// The first word is the pointer to the actual content, and the second the /// length of the slice. fn slice() { - let mut context = create_context(); + let context = create_context(); - let s_slice = Type::get_slice(&mut context).size(&context); + let s_slice = Type::get_slice(&context).size(&context); assert_eq!(s_slice.in_bytes(), 16); assert_eq!(s_slice.in_bytes(), s_slice.in_bytes_aligned()); diff --git a/sway-ir/src/optimize/fn_dedup.rs b/sway-ir/src/optimize/fn_dedup.rs index 35608886944..0acbee5a8d9 100644 --- a/sway-ir/src/optimize/fn_dedup.rs +++ b/sway-ir/src/optimize/fn_dedup.rs @@ -143,10 +143,7 @@ fn hash_fn(context: &Context, function: Function, eq_class: &mut EqClass) -> u64 get_localised_id(true_block.block, localised_block_id).hash(state); get_localised_id(false_block.block, localised_block_id).hash(state); } - crate::InstOp::ContractCall { - return_type, name, .. - } => { - return_type.hash(state); + crate::InstOp::ContractCall { name, .. } => { name.hash(state); } crate::InstOp::FuelVm(fuel_vm_inst) => match fuel_vm_inst { @@ -165,6 +162,10 @@ fn hash_fn(context: &Context, function: Function, eq_class: &mut EqClass) -> u64 crate::FuelVmInstruction::WideBinaryOp { op, .. } => op.hash(state), crate::FuelVmInstruction::WideModularOp { op, .. } => op.hash(state), crate::FuelVmInstruction::WideCmpOp { op, .. } => op.hash(state), + crate::FuelVmInstruction::Retd { ptr, len } => { + ptr.hash(state); + len.hash(state); + } }, crate::InstOp::GetLocal(local) => function .lookup_local_name(context, local) diff --git a/sway-ir/src/optimize/inline.rs b/sway-ir/src/optimize/inline.rs index 29c97517a3a..a98893aa1bd 100644 --- a/sway-ir/src/optimize/inline.rs +++ b/sway-ir/src/optimize/inline.rs @@ -607,6 +607,9 @@ fn inline_instruction( FuelVmInstruction::WideCmpOp { op, arg1, arg2 } => new_block .append(context) .wide_cmp_op(op, map_value(arg1), map_value(arg2)), + FuelVmInstruction::Retd { ptr, len } => new_block + .append(context) + .retd(map_value(ptr), map_value(len)), }, InstOp::GetElemPtr { base, diff --git a/sway-ir/src/parser.rs b/sway-ir/src/parser.rs index 703c3ca2aa5..ee80c1e9a33 100644 --- a/sway-ir/src/parser.rs +++ b/sway-ir/src/parser.rs @@ -1245,7 +1245,7 @@ mod ir_builder { .append(context) .contract_call( ir_ty, - name, + Some(name), *val_map.get(¶ms).unwrap(), *val_map.get(&coins).unwrap(), *val_map.get(&asset_id).unwrap(), diff --git a/sway-ir/src/printer.rs b/sway-ir/src/printer.rs index 285b22dd6e7..a346b42969a 100644 --- a/sway-ir/src/printer.rs +++ b/sway-ir/src/printer.rs @@ -593,7 +593,7 @@ fn instruction_to_doc<'a>( "{} = contract_call {} {} {}, {}, {}, {}", namer.name(context, ins_value), return_type.as_string(context), - name, + name.as_deref().unwrap_or(""), namer.name(context, params), namer.name(context, coins), namer.name(context, asset_id), @@ -816,7 +816,6 @@ fn instruction_to_doc<'a>( .append(md_namer.md_idx_to_doc(context, metadata)), )) } - FuelVmInstruction::WideCmpOp { op, arg1, arg2 } => { let pred_str = match op { Predicate::Equal => "eq", @@ -835,6 +834,18 @@ fn instruction_to_doc<'a>( .append(md_namer.md_idx_to_doc(context, metadata)), )) } + FuelVmInstruction::Retd { ptr, len } => { + maybe_constant_to_doc(context, md_namer, namer, ptr) + .append(maybe_constant_to_doc(context, md_namer, namer, len)) + .append(Doc::line( + Doc::text(format!( + "retd {} {}", + namer.name(context, ptr), + namer.name(context, len), + )) + .append(md_namer.md_idx_to_doc(context, metadata)), + )) + } }, InstOp::GetElemPtr { base, diff --git a/sway-ir/src/verify.rs b/sway-ir/src/verify.rs index 7c8e08384c3..3ad7849fb1e 100644 --- a/sway-ir/src/verify.rs +++ b/sway-ir/src/verify.rs @@ -111,13 +111,21 @@ impl<'eng> Context<'eng> { } } - InstructionVerifier { + let r = InstructionVerifier { context: self, cur_module, cur_function, cur_block, } - .verify_instructions()?; + .verify_instructions(); + + if r.is_err() { + println!("{}", self); + println!("{}", cur_function.get_name(self)); + println!("{}", cur_block.get_label(self)); + } + + r?; let (last_is_term, num_terms) = cur_block @@ -218,7 +226,6 @@ impl<'a, 'eng> InstructionVerifier<'a, 'eng> { gas, .. } => self.verify_contract_call(params, coins, asset_id, gas)?, - // XXX move the fuelvm verification into a module InstOp::FuelVm(fuel_vm_instr) => match fuel_vm_instr { FuelVmInstruction::Gtf { index, tx_field_id } => { @@ -278,6 +285,7 @@ impl<'a, 'eng> InstructionVerifier<'a, 'eng> { FuelVmInstruction::WideCmpOp { op, arg1, arg2 } => { self.verify_wide_cmp(op, arg1, arg2)? } + FuelVmInstruction::Retd { .. } => (), }, InstOp::GetElemPtr { base, @@ -669,51 +677,55 @@ impl<'a, 'eng> InstructionVerifier<'a, 'eng> { asset_id: &Value, gas: &Value, ) -> Result<(), IrError> { - // - The params must be a struct with the B256 address, u64 selector and u64 address to - // user args. - // - The coins and gas must be u64s. - // - The asset_id must be a B256 - let fields = params - .get_type(self.context) - .and_then(|ty| ty.get_pointee_type(self.context)) - .map_or_else(std::vec::Vec::new, |ty| ty.get_field_types(self.context)); - if fields.len() != 3 - || !fields[0].is_b256(self.context) - || !fields[1].is_uint64(self.context) - || !fields[2].is_uint64(self.context) - { - Err(IrError::VerifyContractCallBadTypes("params".to_owned())) - } else { - Ok(()) - } - .and_then(|_| { - if coins - .get_type(self.context) - .is(Type::is_uint64, self.context) - { - Ok(()) - } else { - Err(IrError::VerifyContractCallBadTypes("coins".to_owned())) - } - }) - .and_then(|_| { - if asset_id + if !self.context.experimental.new_encoding { + // - The params must be a struct with the B256 address, u64 selector and u64 address to + // user args. + // - The coins and gas must be u64s. + // - The asset_id must be a B256 + let fields = params .get_type(self.context) .and_then(|ty| ty.get_pointee_type(self.context)) - .is(Type::is_b256, self.context) + .map_or_else(std::vec::Vec::new, |ty| ty.get_field_types(self.context)); + if fields.len() != 3 + || !fields[0].is_b256(self.context) + || !fields[1].is_uint64(self.context) + || !fields[2].is_uint64(self.context) { - Ok(()) + Err(IrError::VerifyContractCallBadTypes("params".to_owned())) } else { - Err(IrError::VerifyContractCallBadTypes("asset_id".to_owned())) - } - }) - .and_then(|_| { - if gas.get_type(self.context).is(Type::is_uint64, self.context) { Ok(()) - } else { - Err(IrError::VerifyContractCallBadTypes("gas".to_owned())) } - }) + .and_then(|_| { + if coins + .get_type(self.context) + .is(Type::is_uint64, self.context) + { + Ok(()) + } else { + Err(IrError::VerifyContractCallBadTypes("coins".to_owned())) + } + }) + .and_then(|_| { + if asset_id + .get_type(self.context) + .and_then(|ty| ty.get_pointee_type(self.context)) + .is(Type::is_b256, self.context) + { + Ok(()) + } else { + Err(IrError::VerifyContractCallBadTypes("asset_id".to_owned())) + } + }) + .and_then(|_| { + if gas.get_type(self.context).is(Type::is_uint64, self.context) { + Ok(()) + } else { + Err(IrError::VerifyContractCallBadTypes("gas".to_owned())) + } + }) + } else { + Ok(()) + } } fn verify_get_elem_ptr( @@ -804,8 +816,16 @@ impl<'a, 'eng> InstructionVerifier<'a, 'eng> { fn verify_load(&self, src_val: &Value) -> Result<(), IrError> { // Just confirm `src_val` is a pointer. - self.get_ptr_type(src_val, IrError::VerifyLoadFromNonPointer) - .map(|_| ()) + let r = self + .get_ptr_type(src_val, IrError::VerifyLoadFromNonPointer) + .map(|_| ()); + + if r.is_err() { + let meta = src_val.get_metadata(self.context).unwrap(); + dbg!(&self.context.metadata[meta.0], &r); + } + + r } fn verify_log(&self, log_val: &Value, log_ty: &Type, log_id: &Value) -> Result<(), IrError> { diff --git a/sway-lib-core/generate.sh b/sway-lib-core/generate.sh new file mode 100755 index 00000000000..76c98b46c36 --- /dev/null +++ b/sway-lib-core/generate.sh @@ -0,0 +1,89 @@ +#! /bin/bash + +# Needs to exist at least one line between them +remove_generated_code() { + START=`grep -n "BEGIN $1" ./src/codec.sw` + START=${START%:*} + END=`grep -n "END $1" ./src/codec.sw` + END=${END%:*} + sed -i "$((START+1)),$((END-1))d" ./src/codec.sw +} + +remove_generated_code "STRARRAY_ENCODE" +START=1 +END=64 +for ((i=END;i>=START;i--)); do + CODE="impl AbiEncode for str[$i] { fn abi_encode(self, ref mut buffer: Buffer) { use ::str::*; let s = from_str_array(self); let len = s.len(); let ptr = s.as_ptr(); let mut i = 0; while i < len { let byte = ptr.add::(i).read::(); buffer.push(byte); i += 1; } } }" + sed -i "s/\/\/ BEGIN STRARRAY_ENCODE/\/\/ BEGIN STRARRAY_ENCODE\n$CODE/g" ./src/codec.sw +done + +remove_generated_code "STRARRAY_DECODE" +START=1 +END=64 +for ((i=END;i>=START;i--)); do + CODE="impl AbiDecode for str[$i] { fn abi_decode(ref mut buffer: BufferReader) -> str[$i] { let data = buffer.read_bytes($i); asm(s: data.ptr()) { s: str[$i] } } }" + sed -i "s/\/\/ BEGIN STRARRAY_DECODE/\/\/ BEGIN STRARRAY_DECODE\n$CODE/g" ./src/codec.sw +done + +generate_tuple_decode() { + local CODE="impl<" + + local elements=("$1") + for element in ${elements[@]} + do + CODE="$CODE $element," + done + + CODE="$CODE> AbiDecode for (" + + for element in ${elements[@]} + do + CODE="$CODE $element," + done + + CODE="$CODE) where " + + for element in ${elements[@]} + do + CODE="$CODE $element: AbiDecode, " + done + + CODE="$CODE{ fn abi_decode(ref mut buffer: BufferReader) -> Self { (" + + for element in ${elements[@]} + do + CODE="$CODE $element::abi_decode(buffer)," + done + + CODE="$CODE) } }" + + sed -i "s/\/\/ BEGIN TUPLES_DECODE/\/\/ BEGIN TUPLES_DECODE\n$CODE/g" ./src/codec.sw +} + +remove_generated_code "TUPLES_DECODE" +generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z" +generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T U V W X Y" +generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T U V W X" +generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T U V W" +generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T U V" +generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T U" +generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S T" +generate_tuple_decode "A B C D E F G H I J K L M N O P Q R S" +generate_tuple_decode "A B C D E F G H I J K L M N O P Q R" +generate_tuple_decode "A B C D E F G H I J K L M N O P Q" +generate_tuple_decode "A B C D E F G H I J K L M N O P" +generate_tuple_decode "A B C D E F G H I J K L M N O" +generate_tuple_decode "A B C D E F G H I J K L M N" +generate_tuple_decode "A B C D E F G H I J K L M" +generate_tuple_decode "A B C D E F G H I J K L" +generate_tuple_decode "A B C D E F G H I J K" +generate_tuple_decode "A B C D E F G H I J" +generate_tuple_decode "A B C D E F G H I" +generate_tuple_decode "A B C D E F G H" +generate_tuple_decode "A B C D E F G" +generate_tuple_decode "A B C D E F" +generate_tuple_decode "A B C D E" +generate_tuple_decode "A B C D" +generate_tuple_decode "A B C" +generate_tuple_decode "A B" +generate_tuple_decode "A" diff --git a/sway-lib-core/src/codec.sw b/sway-lib-core/src/codec.sw index 56f6f1e7db3..daa723f69cf 100644 --- a/sway-lib-core/src/codec.sw +++ b/sway-lib-core/src/codec.sw @@ -41,14 +41,120 @@ impl AsRawSlice for Buffer { } } +pub struct BufferReader { + ptr: raw_ptr, + pos: u64, +} + +impl BufferReader { + pub fn from_parts(ptr: raw_ptr, _len: u64) -> BufferReader { + BufferReader { ptr, pos: 0 } + } + + pub fn from_first_parameter() -> BufferReader { + const FIRST_PARAMETER_OFFSET: u64 = 73; + + let ptr = asm() { + fp: raw_ptr + }; + let ptr = ptr.add::(FIRST_PARAMETER_OFFSET); + let ptr = ptr.read::(); + + BufferReader { + ptr: asm(ptr: ptr) { + ptr: raw_ptr + }, + pos: 0, + } + } + + pub fn from_second_parameter() -> BufferReader { + const SECOND_PARAMETER_OFFSET: u64 = 74; + + let ptr = asm() { + fp: raw_ptr + }; + let ptr = ptr.add::(SECOND_PARAMETER_OFFSET); + let ptr = ptr.read::(); + + BufferReader { + ptr: asm(ptr: ptr) { + ptr: raw_ptr + }, + pos: 0, + } + } + + pub fn from_script_data() -> BufferReader { + let ptr = __gtf::(0, 0xA); // SCRIPT_DATA + let _len = __gtf::(0, 0x4); // SCRIPT_DATA_LEN + BufferReader { ptr, pos: 0 } + } + + pub fn read_bytes(ref mut self, count: u64) -> raw_slice { + let next_pos = self.pos + count; + + let ptr = self.ptr.add::(self.pos); + let slice = asm(ptr: (ptr, count)) { + ptr: raw_slice + }; + + self.pos = next_pos; + + slice + } + + pub fn read(ref mut self) -> T { + let ptr = self.ptr.add::(self.pos); + + let size = __size_of::(); + let next_pos = self.pos + size; + + if __is_reference_type::() { + let v = asm(ptr: ptr) { + ptr: T + }; + self.pos = next_pos; + v + } else if size == 1 { + let v = asm(ptr: ptr, val) { + lb val ptr i0; + val: T + }; + self.pos = next_pos; + v + } else { + let v = asm(ptr: ptr, val) { + lw val ptr i0; + val: T + }; + self.pos = next_pos; + v + } + } + + pub fn decode(ref mut self) -> T + where + T: AbiDecode, + { + T::abi_decode(self) + } +} + +// Encode + pub trait AbiEncode { fn abi_encode(self, ref mut buffer: Buffer); } -impl AbiEncode for () { - fn abi_encode(self, ref mut _buffer: Buffer) {} +impl AbiEncode for bool { + fn abi_encode(self, ref mut buffer: Buffer) { + buffer.push(self); + } } +// Encode Numbers + impl AbiEncode for b256 { fn abi_encode(self, ref mut buffer: Buffer) { let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) { @@ -61,12 +167,6 @@ impl AbiEncode for b256 { } } -impl AbiEncode for bool { - fn abi_encode(self, ref mut buffer: Buffer) { - buffer.push(self); - } -} - impl AbiEncode for u256 { fn abi_encode(self, ref mut buffer: Buffer) { let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) { @@ -147,6 +247,8 @@ impl AbiEncode for u8 { } } +// Encode str slice and str arrays + impl AbiEncode for str { fn abi_encode(self, ref mut buffer: Buffer) { use ::str::*; @@ -164,36 +266,17 @@ impl AbiEncode for str { } } -impl AbiEncode for raw_slice { - fn abi_encode(self, ref mut buffer: Buffer) { - let len = self.number_of_bytes(); - buffer.push(len); - - let ptr = self.ptr(); - - let mut i = 0; - while i < len { - let byte = ptr.add::(i).read::(); - buffer.push(byte); - i += 1; - } - } -} - -// str arrays - impl AbiEncode for str[0] { fn abi_encode(self, ref mut _buffer: Buffer) {} } +// BEGIN STRARRAY_ENCODE impl AbiEncode for str[1] { fn abi_encode(self, ref mut buffer: Buffer) { use ::str::*; let s = from_str_array(self); - let len = s.len(); let ptr = s.as_ptr(); - let mut i = 0; while i < len { let byte = ptr.add::(i).read::(); @@ -202,15 +285,12 @@ impl AbiEncode for str[1] { } } } - impl AbiEncode for str[2] { fn abi_encode(self, ref mut buffer: Buffer) { use ::str::*; let s = from_str_array(self); - let len = s.len(); let ptr = s.as_ptr(); - let mut i = 0; while i < len { let byte = ptr.add::(i).read::(); @@ -219,15 +299,12 @@ impl AbiEncode for str[2] { } } } - impl AbiEncode for str[3] { fn abi_encode(self, ref mut buffer: Buffer) { use ::str::*; let s = from_str_array(self); - let len = s.len(); let ptr = s.as_ptr(); - let mut i = 0; while i < len { let byte = ptr.add::(i).read::(); @@ -236,15 +313,12 @@ impl AbiEncode for str[3] { } } } - impl AbiEncode for str[4] { fn abi_encode(self, ref mut buffer: Buffer) { use ::str::*; let s = from_str_array(self); - let len = s.len(); let ptr = s.as_ptr(); - let mut i = 0; while i < len { let byte = ptr.add::(i).read::(); @@ -253,15 +327,12 @@ impl AbiEncode for str[4] { } } } - impl AbiEncode for str[5] { fn abi_encode(self, ref mut buffer: Buffer) { use ::str::*; let s = from_str_array(self); - let len = s.len(); let ptr = s.as_ptr(); - let mut i = 0; while i < len { let byte = ptr.add::(i).read::(); @@ -270,162 +341,2595 @@ impl AbiEncode for str[5] { } } } - -// arrays and slices - -impl AbiEncode for [T; 1] -where - T: AbiEncode, -{ +impl AbiEncode for str[6] { fn abi_encode(self, ref mut buffer: Buffer) { - self[0].abi_encode(buffer); + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } } } - -impl AbiEncode for [T; 2] -where - T: AbiEncode, -{ +impl AbiEncode for str[7] { fn abi_encode(self, ref mut buffer: Buffer) { - self[0].abi_encode(buffer); - self[1].abi_encode(buffer); + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } } } - -impl AbiEncode for [T; 3] -where - T: AbiEncode, -{ +impl AbiEncode for str[8] { fn abi_encode(self, ref mut buffer: Buffer) { - self[0].abi_encode(buffer); - self[1].abi_encode(buffer); - self[2].abi_encode(buffer); + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } } } - -impl AbiEncode for [T; 4] -where - T: AbiEncode, -{ +impl AbiEncode for str[9] { fn abi_encode(self, ref mut buffer: Buffer) { - self[0].abi_encode(buffer); - self[1].abi_encode(buffer); - self[2].abi_encode(buffer); - self[3].abi_encode(buffer); + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } } } - -impl AbiEncode for [T; 5] -where - T: AbiEncode, -{ +impl AbiEncode for str[10] { fn abi_encode(self, ref mut buffer: Buffer) { - self[0].abi_encode(buffer); - self[1].abi_encode(buffer); - self[2].abi_encode(buffer); - self[3].abi_encode(buffer); - self[4].abi_encode(buffer); + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } } } - -// Tuples - -impl AbiEncode for (A, B) -where - A: AbiEncode, - B: AbiEncode, -{ +impl AbiEncode for str[11] { fn abi_encode(self, ref mut buffer: Buffer) { - self.0.abi_encode(buffer); - self.1.abi_encode(buffer); + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } } } - -impl AbiEncode for (A, B, C) -where - A: AbiEncode, - B: AbiEncode, - C: AbiEncode, -{ +impl AbiEncode for str[12] { fn abi_encode(self, ref mut buffer: Buffer) { - self.0.abi_encode(buffer); - self.1.abi_encode(buffer); - self.2.abi_encode(buffer); + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } } } - -impl AbiEncode for (A, B, C, D) -where - A: AbiEncode, - B: AbiEncode, - C: AbiEncode, - D: AbiEncode, -{ +impl AbiEncode for str[13] { fn abi_encode(self, ref mut buffer: Buffer) { - self.0.abi_encode(buffer); - self.1.abi_encode(buffer); - self.2.abi_encode(buffer); - self.3.abi_encode(buffer); + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } } } - -impl AbiEncode for (A, B, C, D, E) -where - A: AbiEncode, - B: AbiEncode, - C: AbiEncode, - D: AbiEncode, - E: AbiEncode, -{ +impl AbiEncode for str[14] { fn abi_encode(self, ref mut buffer: Buffer) { - self.0.abi_encode(buffer); - self.1.abi_encode(buffer); - self.2.abi_encode(buffer); - self.3.abi_encode(buffer); - self.4.abi_encode(buffer); + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } } } +impl AbiEncode for str[15] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[16] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[17] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[18] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[19] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[20] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[21] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[22] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[23] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[24] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[25] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[26] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[27] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[28] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[29] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[30] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[31] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[32] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[33] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[34] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[35] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[36] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[37] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[38] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[39] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[40] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[41] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[42] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[43] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[44] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[45] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[46] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[47] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[48] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[49] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[50] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[51] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[52] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[53] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[54] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[55] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[56] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[57] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[58] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[59] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[60] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[61] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[62] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[63] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +impl AbiEncode for str[64] { + fn abi_encode(self, ref mut buffer: Buffer) { + use ::str::*; + let s = from_str_array(self); + let len = s.len(); + let ptr = s.as_ptr(); + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} +// END STRARRAY_ENCODE + +// Encode Arrays and Slices + +impl AbiEncode for raw_slice { + fn abi_encode(self, ref mut buffer: Buffer) { + let len = self.number_of_bytes(); + buffer.push(len); + + let ptr = self.ptr(); + + let mut i = 0; + while i < len { + let byte = ptr.add::(i).read::(); + buffer.push(byte); + i += 1; + } + } +} + +impl AbiEncode for [T; 0] +where + T: AbiEncode, +{ + fn abi_encode(self, ref mut _buffer: Buffer) {} +} + +impl AbiEncode for [T; 1] +where + T: AbiEncode, +{ + fn abi_encode(self, ref mut buffer: Buffer) { + self[0].abi_encode(buffer); + } +} + +impl AbiEncode for [T; 2] +where + T: AbiEncode, +{ + fn abi_encode(self, ref mut buffer: Buffer) { + self[0].abi_encode(buffer); + self[1].abi_encode(buffer); + } +} + +impl AbiEncode for [T; 3] +where + T: AbiEncode, +{ + fn abi_encode(self, ref mut buffer: Buffer) { + self[0].abi_encode(buffer); + self[1].abi_encode(buffer); + self[2].abi_encode(buffer); + } +} + +impl AbiEncode for [T; 4] +where + T: AbiEncode, +{ + fn abi_encode(self, ref mut buffer: Buffer) { + self[0].abi_encode(buffer); + self[1].abi_encode(buffer); + self[2].abi_encode(buffer); + self[3].abi_encode(buffer); + } +} + +impl AbiEncode for [T; 5] +where + T: AbiEncode, +{ + fn abi_encode(self, ref mut buffer: Buffer) { + self[0].abi_encode(buffer); + self[1].abi_encode(buffer); + self[2].abi_encode(buffer); + self[3].abi_encode(buffer); + self[4].abi_encode(buffer); + } +} + +// Encode Tuples + +impl AbiEncode for () { + fn abi_encode(self, ref mut _buffer: Buffer) {} +} + +impl AbiEncode for (A, ) +where + A: AbiEncode, +{ + fn abi_encode(self, ref mut buffer: Buffer) { + self.0.abi_encode(buffer); + } +} + +impl AbiEncode for (A, B) +where + A: AbiEncode, + B: AbiEncode, +{ + fn abi_encode(self, ref mut buffer: Buffer) { + self.0.abi_encode(buffer); + self.1.abi_encode(buffer); + } +} + +impl AbiEncode for (A, B, C) +where + A: AbiEncode, + B: AbiEncode, + C: AbiEncode, +{ + fn abi_encode(self, ref mut buffer: Buffer) { + self.0.abi_encode(buffer); + self.1.abi_encode(buffer); + self.2.abi_encode(buffer); + } +} + +impl AbiEncode for (A, B, C, D) +where + A: AbiEncode, + B: AbiEncode, + C: AbiEncode, + D: AbiEncode, +{ + fn abi_encode(self, ref mut buffer: Buffer) { + self.0.abi_encode(buffer); + self.1.abi_encode(buffer); + self.2.abi_encode(buffer); + self.3.abi_encode(buffer); + } +} + +impl AbiEncode for (A, B, C, D, E) +where + A: AbiEncode, + B: AbiEncode, + C: AbiEncode, + D: AbiEncode, + E: AbiEncode, +{ + fn abi_encode(self, ref mut buffer: Buffer) { + self.0.abi_encode(buffer); + self.1.abi_encode(buffer); + self.2.abi_encode(buffer); + self.3.abi_encode(buffer); + self.4.abi_encode(buffer); + } +} + +impl AbiEncode for (A, B, C, D, E, F) +where + A: AbiEncode, + B: AbiEncode, + C: AbiEncode, + D: AbiEncode, + E: AbiEncode, + F: AbiEncode, +{ + fn abi_encode(self, ref mut buffer: Buffer) { + self.0.abi_encode(buffer); + self.1.abi_encode(buffer); + self.2.abi_encode(buffer); + self.3.abi_encode(buffer); + self.4.abi_encode(buffer); + self.5.abi_encode(buffer); + } +} + +pub fn encode(item: T) -> raw_slice +where + T: AbiEncode, +{ + let mut buffer = Buffer::new(); + item.abi_encode(buffer); + buffer.as_raw_slice() +} + +pub fn abi_decode(data: raw_slice) -> T +where + T: AbiDecode, +{ + let mut buffer = BufferReader::from_parts(data.ptr(), data.len::()); + T::abi_decode(buffer) +} + +fn assert_encoding(value: T, expected: SLICE) +where + T: AbiEncode, +{ + let len = __size_of::(); + + if len == 0 { + __revert(0); + } + + let expected = raw_slice::from_parts::(__addr_of(expected), len); + let actual = encode(value); + + if actual.len::() != expected.len::() { + __revert(0); + } + + let result = asm( + result, + expected: expected.ptr(), + actual: actual.ptr(), + len: len, + ) { + meq result expected actual len; + result: bool + }; + + if !result { + __revert(0); + } +} + +// Decode + +pub trait AbiDecode { + fn abi_decode(ref mut buffer: BufferReader) -> Self; +} + +impl AbiDecode for b256 { + fn abi_decode(ref mut buffer: BufferReader) -> b256 { + buffer.read::() + } +} + +impl AbiDecode for u256 { + fn abi_decode(ref mut buffer: BufferReader) -> u256 { + buffer.read::() + } +} + +impl AbiDecode for u64 { + fn abi_decode(ref mut buffer: BufferReader) -> u64 { + buffer.read::() + } +} + +impl AbiDecode for u32 { + fn abi_decode(ref mut buffer: BufferReader) -> u32 { + buffer.read::() + } +} + +impl AbiDecode for u16 { + fn abi_decode(ref mut buffer: BufferReader) -> u16 { + buffer.read::() + } +} + +impl AbiDecode for u8 { + fn abi_decode(ref mut buffer: BufferReader) -> u8 { + buffer.read::() + } +} + +impl AbiDecode for bool { + fn abi_decode(ref mut buffer: BufferReader) -> bool { + buffer.read::() + } +} + +impl AbiDecode for raw_slice { + fn abi_decode(ref mut buffer: BufferReader) -> raw_slice { + let len = u64::abi_decode(buffer); + let data = buffer.read_bytes(len); + asm(s: (data.ptr(), len)) { + s: raw_slice + } + } +} + +impl AbiDecode for str { + fn abi_decode(ref mut buffer: BufferReader) -> str { + let len = u64::abi_decode(buffer); + let data = buffer.read_bytes(len); + asm(s: (data.ptr(), len)) { + s: str + } + } +} + +// BEGIN STRARRAY_DECODE +impl AbiDecode for str[1] { + fn abi_decode(ref mut buffer: BufferReader) -> str[1] { + let data = buffer.read_bytes(1); + asm(s: data.ptr()) { + s: str[1] + } + } +} +impl AbiDecode for str[2] { + fn abi_decode(ref mut buffer: BufferReader) -> str[2] { + let data = buffer.read_bytes(2); + asm(s: data.ptr()) { + s: str[2] + } + } +} +impl AbiDecode for str[3] { + fn abi_decode(ref mut buffer: BufferReader) -> str[3] { + let data = buffer.read_bytes(3); + asm(s: data.ptr()) { + s: str[3] + } + } +} +impl AbiDecode for str[4] { + fn abi_decode(ref mut buffer: BufferReader) -> str[4] { + let data = buffer.read_bytes(4); + asm(s: data.ptr()) { + s: str[4] + } + } +} +impl AbiDecode for str[5] { + fn abi_decode(ref mut buffer: BufferReader) -> str[5] { + let data = buffer.read_bytes(5); + asm(s: data.ptr()) { + s: str[5] + } + } +} +impl AbiDecode for str[6] { + fn abi_decode(ref mut buffer: BufferReader) -> str[6] { + let data = buffer.read_bytes(6); + asm(s: data.ptr()) { + s: str[6] + } + } +} +impl AbiDecode for str[7] { + fn abi_decode(ref mut buffer: BufferReader) -> str[7] { + let data = buffer.read_bytes(7); + asm(s: data.ptr()) { + s: str[7] + } + } +} +impl AbiDecode for str[8] { + fn abi_decode(ref mut buffer: BufferReader) -> str[8] { + let data = buffer.read_bytes(8); + asm(s: data.ptr()) { + s: str[8] + } + } +} +impl AbiDecode for str[9] { + fn abi_decode(ref mut buffer: BufferReader) -> str[9] { + let data = buffer.read_bytes(9); + asm(s: data.ptr()) { + s: str[9] + } + } +} +impl AbiDecode for str[10] { + fn abi_decode(ref mut buffer: BufferReader) -> str[10] { + let data = buffer.read_bytes(10); + asm(s: data.ptr()) { + s: str[10] + } + } +} +impl AbiDecode for str[11] { + fn abi_decode(ref mut buffer: BufferReader) -> str[11] { + let data = buffer.read_bytes(11); + asm(s: data.ptr()) { + s: str[11] + } + } +} +impl AbiDecode for str[12] { + fn abi_decode(ref mut buffer: BufferReader) -> str[12] { + let data = buffer.read_bytes(12); + asm(s: data.ptr()) { + s: str[12] + } + } +} +impl AbiDecode for str[13] { + fn abi_decode(ref mut buffer: BufferReader) -> str[13] { + let data = buffer.read_bytes(13); + asm(s: data.ptr()) { + s: str[13] + } + } +} +impl AbiDecode for str[14] { + fn abi_decode(ref mut buffer: BufferReader) -> str[14] { + let data = buffer.read_bytes(14); + asm(s: data.ptr()) { + s: str[14] + } + } +} +impl AbiDecode for str[15] { + fn abi_decode(ref mut buffer: BufferReader) -> str[15] { + let data = buffer.read_bytes(15); + asm(s: data.ptr()) { + s: str[15] + } + } +} +impl AbiDecode for str[16] { + fn abi_decode(ref mut buffer: BufferReader) -> str[16] { + let data = buffer.read_bytes(16); + asm(s: data.ptr()) { + s: str[16] + } + } +} +impl AbiDecode for str[17] { + fn abi_decode(ref mut buffer: BufferReader) -> str[17] { + let data = buffer.read_bytes(17); + asm(s: data.ptr()) { + s: str[17] + } + } +} +impl AbiDecode for str[18] { + fn abi_decode(ref mut buffer: BufferReader) -> str[18] { + let data = buffer.read_bytes(18); + asm(s: data.ptr()) { + s: str[18] + } + } +} +impl AbiDecode for str[19] { + fn abi_decode(ref mut buffer: BufferReader) -> str[19] { + let data = buffer.read_bytes(19); + asm(s: data.ptr()) { + s: str[19] + } + } +} +impl AbiDecode for str[20] { + fn abi_decode(ref mut buffer: BufferReader) -> str[20] { + let data = buffer.read_bytes(20); + asm(s: data.ptr()) { + s: str[20] + } + } +} +impl AbiDecode for str[21] { + fn abi_decode(ref mut buffer: BufferReader) -> str[21] { + let data = buffer.read_bytes(21); + asm(s: data.ptr()) { + s: str[21] + } + } +} +impl AbiDecode for str[22] { + fn abi_decode(ref mut buffer: BufferReader) -> str[22] { + let data = buffer.read_bytes(22); + asm(s: data.ptr()) { + s: str[22] + } + } +} +impl AbiDecode for str[23] { + fn abi_decode(ref mut buffer: BufferReader) -> str[23] { + let data = buffer.read_bytes(23); + asm(s: data.ptr()) { + s: str[23] + } + } +} +impl AbiDecode for str[24] { + fn abi_decode(ref mut buffer: BufferReader) -> str[24] { + let data = buffer.read_bytes(24); + asm(s: data.ptr()) { + s: str[24] + } + } +} +impl AbiDecode for str[25] { + fn abi_decode(ref mut buffer: BufferReader) -> str[25] { + let data = buffer.read_bytes(25); + asm(s: data.ptr()) { + s: str[25] + } + } +} +impl AbiDecode for str[26] { + fn abi_decode(ref mut buffer: BufferReader) -> str[26] { + let data = buffer.read_bytes(26); + asm(s: data.ptr()) { + s: str[26] + } + } +} +impl AbiDecode for str[27] { + fn abi_decode(ref mut buffer: BufferReader) -> str[27] { + let data = buffer.read_bytes(27); + asm(s: data.ptr()) { + s: str[27] + } + } +} +impl AbiDecode for str[28] { + fn abi_decode(ref mut buffer: BufferReader) -> str[28] { + let data = buffer.read_bytes(28); + asm(s: data.ptr()) { + s: str[28] + } + } +} +impl AbiDecode for str[29] { + fn abi_decode(ref mut buffer: BufferReader) -> str[29] { + let data = buffer.read_bytes(29); + asm(s: data.ptr()) { + s: str[29] + } + } +} +impl AbiDecode for str[30] { + fn abi_decode(ref mut buffer: BufferReader) -> str[30] { + let data = buffer.read_bytes(30); + asm(s: data.ptr()) { + s: str[30] + } + } +} +impl AbiDecode for str[31] { + fn abi_decode(ref mut buffer: BufferReader) -> str[31] { + let data = buffer.read_bytes(31); + asm(s: data.ptr()) { + s: str[31] + } + } +} +impl AbiDecode for str[32] { + fn abi_decode(ref mut buffer: BufferReader) -> str[32] { + let data = buffer.read_bytes(32); + asm(s: data.ptr()) { + s: str[32] + } + } +} +impl AbiDecode for str[33] { + fn abi_decode(ref mut buffer: BufferReader) -> str[33] { + let data = buffer.read_bytes(33); + asm(s: data.ptr()) { + s: str[33] + } + } +} +impl AbiDecode for str[34] { + fn abi_decode(ref mut buffer: BufferReader) -> str[34] { + let data = buffer.read_bytes(34); + asm(s: data.ptr()) { + s: str[34] + } + } +} +impl AbiDecode for str[35] { + fn abi_decode(ref mut buffer: BufferReader) -> str[35] { + let data = buffer.read_bytes(35); + asm(s: data.ptr()) { + s: str[35] + } + } +} +impl AbiDecode for str[36] { + fn abi_decode(ref mut buffer: BufferReader) -> str[36] { + let data = buffer.read_bytes(36); + asm(s: data.ptr()) { + s: str[36] + } + } +} +impl AbiDecode for str[37] { + fn abi_decode(ref mut buffer: BufferReader) -> str[37] { + let data = buffer.read_bytes(37); + asm(s: data.ptr()) { + s: str[37] + } + } +} +impl AbiDecode for str[38] { + fn abi_decode(ref mut buffer: BufferReader) -> str[38] { + let data = buffer.read_bytes(38); + asm(s: data.ptr()) { + s: str[38] + } + } +} +impl AbiDecode for str[39] { + fn abi_decode(ref mut buffer: BufferReader) -> str[39] { + let data = buffer.read_bytes(39); + asm(s: data.ptr()) { + s: str[39] + } + } +} +impl AbiDecode for str[40] { + fn abi_decode(ref mut buffer: BufferReader) -> str[40] { + let data = buffer.read_bytes(40); + asm(s: data.ptr()) { + s: str[40] + } + } +} +impl AbiDecode for str[41] { + fn abi_decode(ref mut buffer: BufferReader) -> str[41] { + let data = buffer.read_bytes(41); + asm(s: data.ptr()) { + s: str[41] + } + } +} +impl AbiDecode for str[42] { + fn abi_decode(ref mut buffer: BufferReader) -> str[42] { + let data = buffer.read_bytes(42); + asm(s: data.ptr()) { + s: str[42] + } + } +} +impl AbiDecode for str[43] { + fn abi_decode(ref mut buffer: BufferReader) -> str[43] { + let data = buffer.read_bytes(43); + asm(s: data.ptr()) { + s: str[43] + } + } +} +impl AbiDecode for str[44] { + fn abi_decode(ref mut buffer: BufferReader) -> str[44] { + let data = buffer.read_bytes(44); + asm(s: data.ptr()) { + s: str[44] + } + } +} +impl AbiDecode for str[45] { + fn abi_decode(ref mut buffer: BufferReader) -> str[45] { + let data = buffer.read_bytes(45); + asm(s: data.ptr()) { + s: str[45] + } + } +} +impl AbiDecode for str[46] { + fn abi_decode(ref mut buffer: BufferReader) -> str[46] { + let data = buffer.read_bytes(46); + asm(s: data.ptr()) { + s: str[46] + } + } +} +impl AbiDecode for str[47] { + fn abi_decode(ref mut buffer: BufferReader) -> str[47] { + let data = buffer.read_bytes(47); + asm(s: data.ptr()) { + s: str[47] + } + } +} +impl AbiDecode for str[48] { + fn abi_decode(ref mut buffer: BufferReader) -> str[48] { + let data = buffer.read_bytes(48); + asm(s: data.ptr()) { + s: str[48] + } + } +} +impl AbiDecode for str[49] { + fn abi_decode(ref mut buffer: BufferReader) -> str[49] { + let data = buffer.read_bytes(49); + asm(s: data.ptr()) { + s: str[49] + } + } +} +impl AbiDecode for str[50] { + fn abi_decode(ref mut buffer: BufferReader) -> str[50] { + let data = buffer.read_bytes(50); + asm(s: data.ptr()) { + s: str[50] + } + } +} +impl AbiDecode for str[51] { + fn abi_decode(ref mut buffer: BufferReader) -> str[51] { + let data = buffer.read_bytes(51); + asm(s: data.ptr()) { + s: str[51] + } + } +} +impl AbiDecode for str[52] { + fn abi_decode(ref mut buffer: BufferReader) -> str[52] { + let data = buffer.read_bytes(52); + asm(s: data.ptr()) { + s: str[52] + } + } +} +impl AbiDecode for str[53] { + fn abi_decode(ref mut buffer: BufferReader) -> str[53] { + let data = buffer.read_bytes(53); + asm(s: data.ptr()) { + s: str[53] + } + } +} +impl AbiDecode for str[54] { + fn abi_decode(ref mut buffer: BufferReader) -> str[54] { + let data = buffer.read_bytes(54); + asm(s: data.ptr()) { + s: str[54] + } + } +} +impl AbiDecode for str[55] { + fn abi_decode(ref mut buffer: BufferReader) -> str[55] { + let data = buffer.read_bytes(55); + asm(s: data.ptr()) { + s: str[55] + } + } +} +impl AbiDecode for str[56] { + fn abi_decode(ref mut buffer: BufferReader) -> str[56] { + let data = buffer.read_bytes(56); + asm(s: data.ptr()) { + s: str[56] + } + } +} +impl AbiDecode for str[57] { + fn abi_decode(ref mut buffer: BufferReader) -> str[57] { + let data = buffer.read_bytes(57); + asm(s: data.ptr()) { + s: str[57] + } + } +} +impl AbiDecode for str[58] { + fn abi_decode(ref mut buffer: BufferReader) -> str[58] { + let data = buffer.read_bytes(58); + asm(s: data.ptr()) { + s: str[58] + } + } +} +impl AbiDecode for str[59] { + fn abi_decode(ref mut buffer: BufferReader) -> str[59] { + let data = buffer.read_bytes(59); + asm(s: data.ptr()) { + s: str[59] + } + } +} +impl AbiDecode for str[60] { + fn abi_decode(ref mut buffer: BufferReader) -> str[60] { + let data = buffer.read_bytes(60); + asm(s: data.ptr()) { + s: str[60] + } + } +} +impl AbiDecode for str[61] { + fn abi_decode(ref mut buffer: BufferReader) -> str[61] { + let data = buffer.read_bytes(61); + asm(s: data.ptr()) { + s: str[61] + } + } +} +impl AbiDecode for str[62] { + fn abi_decode(ref mut buffer: BufferReader) -> str[62] { + let data = buffer.read_bytes(62); + asm(s: data.ptr()) { + s: str[62] + } + } +} +impl AbiDecode for str[63] { + fn abi_decode(ref mut buffer: BufferReader) -> str[63] { + let data = buffer.read_bytes(63); + asm(s: data.ptr()) { + s: str[63] + } + } +} +impl AbiDecode for str[64] { + fn abi_decode(ref mut buffer: BufferReader) -> str[64] { + let data = buffer.read_bytes(64); + asm(s: data.ptr()) { + s: str[64] + } + } +} +// END STRARRAY_DECODE -pub fn encode(item: T) -> raw_slice +impl AbiDecode for [T; 0] where - T: AbiEncode, + T: AbiDecode, { - let mut buffer = Buffer::new(); - item.abi_encode(buffer); - buffer.as_raw_slice() + fn abi_decode(ref mut _buffer: BufferReader) -> [T; 0] { + [] + } } -fn assert_encoding(value: T, expected: SLICE) +impl AbiDecode for [T; 1] where - T: AbiEncode, + T: AbiDecode, { - let len = __size_of::(); + fn abi_decode(ref mut buffer: BufferReader) -> [T; 1] { + [T::abi_decode(buffer)] + } +} - if len == 0 { - __revert(0); +impl AbiDecode for [T; 2] +where + T: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> [T; 2] { + [T::abi_decode(buffer), T::abi_decode(buffer)] } +} - let expected = raw_slice::from_parts::(__addr_of(expected), len); - let actual = encode(value); +impl AbiDecode for [T; 3] +where + T: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> [T; 3] { + [T::abi_decode(buffer), T::abi_decode(buffer), T::abi_decode(buffer)] + } +} - if actual.len::() != expected.len::() { - __revert(0); +impl AbiDecode for [T; 4] +where + T: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> [T; 4] { + [ + T::abi_decode(buffer), + T::abi_decode(buffer), + T::abi_decode(buffer), + T::abi_decode(buffer), + ] } +} - let result = asm( - result, - expected: expected.ptr(), - actual: actual.ptr(), - len: len, - ) { - meq result expected actual len; - result: bool - }; +impl AbiDecode for () { + fn abi_decode(ref mut _buffer: BufferReader) -> () { + () + } +} - if !result { - __revert(0); +// BEGIN TUPLES_DECODE +impl AbiDecode for (A, ) +where + A: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + (A::abi_decode(buffer), ) + } +} +impl AbiDecode for (A, B) +where + A: AbiDecode, + B: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + (A::abi_decode(buffer), B::abi_decode(buffer)) + } +} +impl AbiDecode for (A, B, C) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + (A::abi_decode(buffer), B::abi_decode(buffer), C::abi_decode(buffer)) + } +} +impl AbiDecode for (A, B, C, D) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, + O: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + O::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, + O: AbiDecode, + P: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + O::abi_decode(buffer), + P::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, + O: AbiDecode, + P: AbiDecode, + Q: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + O::abi_decode(buffer), + P::abi_decode(buffer), + Q::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, + O: AbiDecode, + P: AbiDecode, + Q: AbiDecode, + R: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + O::abi_decode(buffer), + P::abi_decode(buffer), + Q::abi_decode(buffer), + R::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, + O: AbiDecode, + P: AbiDecode, + Q: AbiDecode, + R: AbiDecode, + S: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + O::abi_decode(buffer), + P::abi_decode(buffer), + Q::abi_decode(buffer), + R::abi_decode(buffer), + S::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, + O: AbiDecode, + P: AbiDecode, + Q: AbiDecode, + R: AbiDecode, + S: AbiDecode, + T: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + O::abi_decode(buffer), + P::abi_decode(buffer), + Q::abi_decode(buffer), + R::abi_decode(buffer), + S::abi_decode(buffer), + T::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, + O: AbiDecode, + P: AbiDecode, + Q: AbiDecode, + R: AbiDecode, + S: AbiDecode, + T: AbiDecode, + U: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + O::abi_decode(buffer), + P::abi_decode(buffer), + Q::abi_decode(buffer), + R::abi_decode(buffer), + S::abi_decode(buffer), + T::abi_decode(buffer), + U::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, + O: AbiDecode, + P: AbiDecode, + Q: AbiDecode, + R: AbiDecode, + S: AbiDecode, + T: AbiDecode, + U: AbiDecode, + V: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + O::abi_decode(buffer), + P::abi_decode(buffer), + Q::abi_decode(buffer), + R::abi_decode(buffer), + S::abi_decode(buffer), + T::abi_decode(buffer), + U::abi_decode(buffer), + V::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, + O: AbiDecode, + P: AbiDecode, + Q: AbiDecode, + R: AbiDecode, + S: AbiDecode, + T: AbiDecode, + U: AbiDecode, + V: AbiDecode, + W: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + O::abi_decode(buffer), + P::abi_decode(buffer), + Q::abi_decode(buffer), + R::abi_decode(buffer), + S::abi_decode(buffer), + T::abi_decode(buffer), + U::abi_decode(buffer), + V::abi_decode(buffer), + W::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, + O: AbiDecode, + P: AbiDecode, + Q: AbiDecode, + R: AbiDecode, + S: AbiDecode, + T: AbiDecode, + U: AbiDecode, + V: AbiDecode, + W: AbiDecode, + X: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + O::abi_decode(buffer), + P::abi_decode(buffer), + Q::abi_decode(buffer), + R::abi_decode(buffer), + S::abi_decode(buffer), + T::abi_decode(buffer), + U::abi_decode(buffer), + V::abi_decode(buffer), + W::abi_decode(buffer), + X::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, + O: AbiDecode, + P: AbiDecode, + Q: AbiDecode, + R: AbiDecode, + S: AbiDecode, + T: AbiDecode, + U: AbiDecode, + V: AbiDecode, + W: AbiDecode, + X: AbiDecode, + Y: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + O::abi_decode(buffer), + P::abi_decode(buffer), + Q::abi_decode(buffer), + R::abi_decode(buffer), + S::abi_decode(buffer), + T::abi_decode(buffer), + U::abi_decode(buffer), + V::abi_decode(buffer), + W::abi_decode(buffer), + X::abi_decode(buffer), + Y::abi_decode(buffer), + ) + } +} +impl AbiDecode for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z) +where + A: AbiDecode, + B: AbiDecode, + C: AbiDecode, + D: AbiDecode, + E: AbiDecode, + F: AbiDecode, + G: AbiDecode, + H: AbiDecode, + I: AbiDecode, + J: AbiDecode, + K: AbiDecode, + L: AbiDecode, + M: AbiDecode, + N: AbiDecode, + O: AbiDecode, + P: AbiDecode, + Q: AbiDecode, + R: AbiDecode, + S: AbiDecode, + T: AbiDecode, + U: AbiDecode, + V: AbiDecode, + W: AbiDecode, + X: AbiDecode, + Y: AbiDecode, + Z: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Self { + ( + A::abi_decode(buffer), + B::abi_decode(buffer), + C::abi_decode(buffer), + D::abi_decode(buffer), + E::abi_decode(buffer), + F::abi_decode(buffer), + G::abi_decode(buffer), + H::abi_decode(buffer), + I::abi_decode(buffer), + J::abi_decode(buffer), + K::abi_decode(buffer), + L::abi_decode(buffer), + M::abi_decode(buffer), + N::abi_decode(buffer), + O::abi_decode(buffer), + P::abi_decode(buffer), + Q::abi_decode(buffer), + R::abi_decode(buffer), + S::abi_decode(buffer), + T::abi_decode(buffer), + U::abi_decode(buffer), + V::abi_decode(buffer), + W::abi_decode(buffer), + X::abi_decode(buffer), + Y::abi_decode(buffer), + Z::abi_decode(buffer), + ) } } +// END TUPLES_DECODE #[test] fn ok_encode() { @@ -508,3 +3012,63 @@ fn ok_encode() { assert_encoding([255u8; 4], [255u8; 4]); assert_encoding([255u8; 5], [255u8; 5]); } + +pub fn contract_call( + contract_id: b256, + method_name: str, + args: TArgs, + coins: u64, + asset_id: b256, + gas: u64, +) -> T +where + T: AbiDecode, + TArgs: AbiEncode, +{ + let first_parameter = encode(method_name); + let second_parameter = encode(args); + let params = encode(( + contract_id, + asm(a: first_parameter.ptr()) { + a: u64 + }, + asm(a: second_parameter.ptr()) { + a: u64 + }, + )); + + __contract_call(params.ptr(), coins, asset_id, gas); + let ptr = asm() { + ret: raw_ptr + }; + let len = asm() { + retl: u64 + }; + + let mut buffer = BufferReader::from_parts(ptr, len); + T::abi_decode(buffer) +} + +pub fn decode_script_data() -> T +where + T: AbiDecode, +{ + let mut buffer = BufferReader::from_script_data(); + T::abi_decode(buffer) +} + +pub fn decode_first_param() -> T +where + T: AbiDecode, +{ + let mut buffer = BufferReader::from_first_parameter(); + T::abi_decode(buffer) +} + +pub fn decode_second_param() -> T +where + T: AbiDecode, +{ + let mut buffer = BufferReader::from_second_parameter(); + T::abi_decode(buffer) +} diff --git a/sway-lib-core/src/ops.sw b/sway-lib-core/src/ops.sw index 0657e8411a1..1229ca8e649 100644 --- a/sway-lib-core/src/ops.sw +++ b/sway-lib-core/src/ops.sw @@ -1241,3 +1241,19 @@ impl Eq for str { } } } + +fn assert(v: bool) { + if !v { + __revert(0) + } +} + +#[test] +pub fn ok_str_eq() { + assert("" == ""); + assert("a" == "a"); + + assert("a" != ""); + assert("" != "a"); + assert("a" != "b"); +} diff --git a/sway-lib-std/src/assert.sw b/sway-lib-std/src/assert.sw index 9b5916b53d9..a3bb6e3e7f1 100644 --- a/sway-lib-std/src/assert.sw +++ b/sway-lib-std/src/assert.sw @@ -55,6 +55,19 @@ pub fn assert(condition: bool) { /// log("a is equal to b"); /// } /// ``` +#[cfg(experimental_new_encoding = false)] +pub fn assert_eq(v1: T, v2: T) +where + T: Eq, +{ + if (v1 != v2) { + log(v1); + log(v2); + revert(FAILED_ASSERT_EQ_SIGNAL); + } +} + +#[cfg(experimental_new_encoding = true)] pub fn assert_eq(v1: T, v2: T) where T: Eq + AbiEncode, @@ -86,6 +99,19 @@ where /// log("a is not equal to b"); /// } /// ``` +#[cfg(experimental_new_encoding = false)] +pub fn assert_ne(v1: T, v2: T) +where + T: Eq, +{ + if (v1 == v2) { + log(v1); + log(v2); + revert(FAILED_ASSERT_NE_SIGNAL); + } +} + +#[cfg(experimental_new_encoding = true)] pub fn assert_ne(v1: T, v2: T) where T: Eq + AbiEncode, diff --git a/sway-lib-std/src/bytes.sw b/sway-lib-std/src/bytes.sw index 720ff610014..1101c5c2000 100644 --- a/sway-lib-std/src/bytes.sw +++ b/sway-lib-std/src/bytes.sw @@ -2,7 +2,7 @@ library; use ::{alloc::{alloc_bytes, realloc_bytes}, vec::Vec}; -use ::assert::assert; +use ::assert::{assert, assert_eq}; use ::intrinsics::size_of_val; use ::option::Option::{self, *}; use ::convert::{From, Into, *}; @@ -920,6 +920,20 @@ impl AbiEncode for Bytes { } } +impl AbiDecode for Bytes { + fn abi_decode(ref mut buffer: BufferReader) -> Bytes { + let len = u64::abi_decode(buffer); + let data = buffer.read_bytes(len); + Bytes { + buf: RawBytes { + ptr: data.ptr(), + cap: len, + }, + len, + } + } +} + // Tests // fn setup() -> (Bytes, u8, u8, u8) { @@ -938,6 +952,7 @@ fn test_new_bytes() { let bytes = Bytes::new(); assert(bytes.len() == 0); } + #[test()] fn test_push() { let (_, a, b, c) = setup(); @@ -949,6 +964,7 @@ fn test_push() { bytes.push(c); assert(bytes.len() == 3); } + #[test()] fn test_pop() { let (mut bytes, a, b, c) = setup(); @@ -988,11 +1004,13 @@ fn test_pop() { assert(bytes.pop().is_none() == true); assert(bytes.len() == 0); } + #[test()] fn test_len() { let (mut bytes, _, _, _) = setup(); assert(bytes.len() == 3); } + #[test()] fn test_clear() { let (mut bytes, _, _, _) = setup(); @@ -1002,6 +1020,7 @@ fn test_clear() { assert(bytes.len() == 0); } + #[test()] fn test_packing() { let mut bytes = Bytes::new(); @@ -1356,3 +1375,12 @@ fn test_into_b256() { assert(value == expected); } + +#[test] +pub fn test_encode_decode() { + let initial = 0x3333333333333333333333333333333333333333333333333333333333333333; + let initial: Bytes = Bytes::from(initial); + let decoded = abi_decode::(encode(initial)); + + assert_eq(decoded, initial); +} diff --git a/sway-lib-std/src/identity.sw b/sway-lib-std/src/identity.sw index b800b0faa05..18d0448d871 100644 --- a/sway-lib-std/src/identity.sw +++ b/sway-lib-std/src/identity.sw @@ -2,6 +2,7 @@ //! The use of this type allows for handling interactions with contracts and addresses in a unified manner. library; +use core::codec::*; use ::assert::assert; use ::address::Address; use ::alias::SubId; diff --git a/sway-lib-std/src/vec.sw b/sway-lib-std/src/vec.sw index 53d8dde9906..bdd09c50e63 100644 --- a/sway-lib-std/src/vec.sw +++ b/sway-lib-std/src/vec.sw @@ -664,6 +664,26 @@ where } } +impl AbiDecode for Vec +where + T: AbiDecode, +{ + fn abi_decode(ref mut buffer: BufferReader) -> Vec { + let mut v = Vec::new(); + + let len = u64::abi_decode(buffer); + + let mut i = 0; + while i < len { + let item = T::abi_decode(buffer); + v.push(item); + i += 1; + } + + v + } +} + pub struct VecIter { values: Vec, index: u64, diff --git a/sway-lsp/benches/lsp_benchmarks/compile.rs b/sway-lsp/benches/lsp_benchmarks/compile.rs index 246ecef7fe8..322ff2ac77e 100644 --- a/sway-lsp/benches/lsp_benchmarks/compile.rs +++ b/sway-lsp/benches/lsp_benchmarks/compile.rs @@ -1,12 +1,16 @@ use criterion::{black_box, criterion_group, Criterion}; use lsp_types::Url; use std::sync::Arc; -use sway_core::Engines; +use sway_core::{Engines, ExperimentalFlags}; use sway_lsp::core::session; const NUM_DID_CHANGE_ITERATIONS: usize = 10; fn benchmarks(c: &mut Criterion) { + let experimental = ExperimentalFlags { + new_encoding: false, + }; + // Load the test project let uri = Url::from_file_path(super::benchmark_dir().join("src/main.sw")).unwrap(); let mut lsp_mode = Some(sway_core::LspConfig { @@ -15,13 +19,17 @@ fn benchmarks(c: &mut Criterion) { c.bench_function("compile", |b| { b.iter(|| { let engines = Engines::default(); - let _ = black_box(session::compile(&uri, &engines, None, lsp_mode.clone()).unwrap()); + let _ = black_box( + session::compile(&uri, &engines, None, lsp_mode.clone(), experimental).unwrap(), + ); }) }); c.bench_function("traverse", |b| { let engines = Engines::default(); - let results = black_box(session::compile(&uri, &engines, None, lsp_mode.clone()).unwrap()); + let results = black_box( + session::compile(&uri, &engines, None, lsp_mode.clone(), experimental).unwrap(), + ); let session = Arc::new(session::Session::new()); b.iter(|| { let _ = @@ -34,8 +42,9 @@ fn benchmarks(c: &mut Criterion) { let engines = Engines::default(); b.iter(|| { for _ in 0..NUM_DID_CHANGE_ITERATIONS { - let _ = - black_box(session::compile(&uri, &engines, None, lsp_mode.clone()).unwrap()); + let _ = black_box( + session::compile(&uri, &engines, None, lsp_mode.clone(), experimental).unwrap(), + ); } }) }); diff --git a/sway-lsp/benches/lsp_benchmarks/mod.rs b/sway-lsp/benches/lsp_benchmarks/mod.rs index 80b7be50b39..8a9d45d32b8 100644 --- a/sway-lsp/benches/lsp_benchmarks/mod.rs +++ b/sway-lsp/benches/lsp_benchmarks/mod.rs @@ -4,9 +4,13 @@ pub mod token_map; use lsp_types::Url; use std::{path::PathBuf, sync::Arc}; +use sway_core::ExperimentalFlags; use sway_lsp::core::session::{self, Session}; pub async fn compile_test_project() -> (Url, Arc) { + let experimental = ExperimentalFlags { + new_encoding: false, + }; let session = Arc::new(Session::new()); let lsp_mode = Some(sway_core::LspConfig { optimized_build: false, @@ -21,6 +25,7 @@ pub async fn compile_test_project() -> (Url, Arc) { None, lsp_mode, session.clone(), + experimental, ) .unwrap(); (uri, session) diff --git a/sway-lsp/src/core/session.rs b/sway-lsp/src/core/session.rs index 7258324bdbf..ee46a1401e1 100644 --- a/sway-lsp/src/core/session.rs +++ b/sway-lsp/src/core/session.rs @@ -37,8 +37,7 @@ use sway_core::{ language::{ lexed::LexedProgram, parsed::{AstNode, ParseProgram}, - ty::{self}, - HasSubmodules, + ty, HasSubmodules, }, BuildTarget, Engines, LspConfig, Namespace, Programs, }; @@ -352,6 +351,7 @@ pub fn compile( engines: &Engines, retrigger_compilation: Option>, lsp_mode: Option, + experimental: sway_core::ExperimentalFlags, ) -> Result, Handler)>, LanguageServerError> { let build_plan = build_plan(uri)?; let tests_enabled = true; @@ -363,6 +363,7 @@ pub fn compile( tests_enabled, engines, retrigger_compilation, + experimental, ) .map_err(LanguageServerError::FailedToCompile) } @@ -455,8 +456,15 @@ pub fn parse_project( retrigger_compilation: Option>, lsp_mode: Option, session: Arc, + experimental: sway_core::ExperimentalFlags, ) -> Result<(), LanguageServerError> { - let results = compile(uri, engines, retrigger_compilation, lsp_mode.clone())?; + let results = compile( + uri, + engines, + retrigger_compilation, + lsp_mode.clone(), + experimental, + )?; if results.last().is_none() { return Err(LanguageServerError::ProgramsIsNone); } @@ -545,7 +553,8 @@ fn create_runnables( // Insert runnable main function if the program is a script. if let ty::TyProgramKind::Script { - ref main_function, .. + entry_function: ref main_function, + .. } = typed_program.kind { let main_function = decl_engine.get_function(main_function); @@ -593,8 +602,17 @@ mod tests { let uri = get_url(&dir); let engines = Engines::default(); let session = Arc::new(Session::new()); - let result = parse_project(&uri, &engines, None, None, session) - .expect_err("expected ManifestFileNotFound"); + let result = parse_project( + &uri, + &engines, + None, + None, + session, + sway_core::ExperimentalFlags { + new_encoding: false, + }, + ) + .expect_err("expected ManifestFileNotFound"); assert!(matches!( result, LanguageServerError::DocumentError( diff --git a/sway-lsp/src/server_state.rs b/sway-lsp/src/server_state.rs index 5715ee17bd7..0c570fe8a73 100644 --- a/sway-lsp/src/server_state.rs +++ b/sway-lsp/src/server_state.rs @@ -107,6 +107,9 @@ impl ServerState { let finished_compilation = self.finished_compilation.clone(); let rx = self.cb_rx.clone(); let last_compilation_state = self.last_compilation_state.clone(); + let experimental = sway_core::ExperimentalFlags { + new_encoding: false, + }; std::thread::spawn(move || { while let Ok(msg) = rx.recv() { match msg { @@ -142,6 +145,7 @@ impl ServerState { Some(retrigger_compilation.clone()), lsp_mode, session.clone(), + experimental, ) { Ok(_) => { mem::swap(&mut *session.engines.write(), &mut engines_clone); diff --git a/sway-parse/src/parse.rs b/sway-parse/src/parse.rs index 34c421fb0f5..986f22bbf73 100644 --- a/sway-parse/src/parse.rs +++ b/sway-parse/src/parse.rs @@ -134,7 +134,10 @@ impl Parse for Ident { match parser.take::() { Some(ident) => { let ident_str = ident.as_str(); - if ident_str.starts_with("__") && Intrinsic::try_from_str(ident_str).is_none() { + + if parser.check_double_underscore + && (ident_str.starts_with("__") && Intrinsic::try_from_str(ident_str).is_none()) + { return Err(parser.emit_error_with_span( ParseErrorKind::InvalidDoubleUnderscore, ident.span(), diff --git a/sway-parse/src/parser.rs b/sway-parse/src/parser.rs index 721086b7dc4..92cf02e03c2 100644 --- a/sway-parse/src/parser.rs +++ b/sway-parse/src/parser.rs @@ -19,6 +19,7 @@ pub struct Parser<'a, 'e> { token_trees: &'a [TokenTree], full_span: Span, handler: &'e Handler, + pub check_double_underscore: bool, } impl<'a, 'e> Parser<'a, 'e> { @@ -27,6 +28,7 @@ impl<'a, 'e> Parser<'a, 'e> { token_trees: token_stream.token_trees(), full_span: token_stream.span(), handler, + check_double_underscore: true, } } @@ -96,6 +98,7 @@ impl<'a, 'e> Parser<'a, 'e> { token_trees: self.token_trees, full_span: self.full_span.clone(), handler: &handler, + check_double_underscore: self.check_double_underscore, }; match parsing_function(&mut fork) { @@ -155,6 +158,7 @@ impl<'a, 'e> Parser<'a, 'e> { token_trees: self.token_trees, full_span: self.full_span.clone(), handler: &handler, + check_double_underscore: self.check_double_underscore, }; match fork.parse() { @@ -188,6 +192,7 @@ impl<'a, 'e> Parser<'a, 'e> { token_trees: self.token_trees, full_span: self.full_span.clone(), handler: &handler, + check_double_underscore: self.check_double_underscore, }; let r = match T::parse(&mut fork) { Ok(result) => { @@ -244,6 +249,7 @@ impl<'a, 'e> Parser<'a, 'e> { token_trees: token_stream.token_trees(), full_span: token_stream.span(), handler: self.handler, + check_double_underscore: self.check_double_underscore, }; Some((parser, span.clone())) } @@ -469,6 +475,7 @@ impl<'original, 'a, 'e> ParseRecoveryStrategies<'original, 'a, 'e> { token_trees: self.fork_token_trees, full_span: self.fork_full_span.clone(), handler: &self.handler, + check_double_underscore: self.original.borrow().check_double_underscore, }; f(&mut p); self.finish(p) diff --git a/sway-types/src/source_engine.rs b/sway-types/src/source_engine.rs index 33ad23d5a8a..dd46df80119 100644 --- a/sway-types/src/source_engine.rs +++ b/sway-types/src/source_engine.rs @@ -100,4 +100,11 @@ impl SourceEngine { .map(|file_name| file_name.to_string_lossy()) .map(|file_name| file_name.to_string()) } + + pub fn all_files(&self) -> Vec { + let s = self.source_to_path_map.read().unwrap(); + let mut v = s.values().cloned().collect::>(); + v.sort(); + v + } } diff --git a/test/Cargo.toml b/test/Cargo.toml index af5eee496f7..80aede9279b 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -7,7 +7,6 @@ edition.workspace = true [dependencies] anyhow = "1.0.41" -assert_matches = "1.5.0" bytes = "1.3.0" clap = { version = "4", features = ["derive", "env"] } colored = "2.0.0" diff --git a/test/src/e2e_vm_tests/harness.rs b/test/src/e2e_vm_tests/harness.rs index 397f53feb78..6c4404e5182 100644 --- a/test/src/e2e_vm_tests/harness.rs +++ b/test/src/e2e_vm_tests/harness.rs @@ -5,7 +5,9 @@ use forc_client::{ op::{deploy, run}, NodeTarget, }; -use forc_pkg::{manifest::build_profile::ExperimentalFlags, BuildProfile, Built, BuiltPackage}; +use forc_pkg::{ + manifest::build_profile::ExperimentalFlags, BuildProfile, Built, BuiltPackage, PrintOpts, +}; use fuel_tx::TransactionBuilder; use fuel_vm::fuel_tx; use fuel_vm::interpreter::Interpreter; @@ -31,15 +33,19 @@ where let mut output = String::new(); // Capture both stdout and stderr to buffers, run the code and save to a string. - let mut buf_stdout = gag::BufferRedirect::stdout().unwrap(); - let mut buf_stderr = gag::BufferRedirect::stderr().unwrap(); - + let buf_stdout = gag::BufferRedirect::stdout(); + let buf_stderr = gag::BufferRedirect::stderr(); let result = func().await; - buf_stdout.read_to_string(&mut output).unwrap(); - buf_stderr.read_to_string(&mut output).unwrap(); - drop(buf_stdout); - drop(buf_stderr); + if let Ok(mut buf_stdout) = buf_stdout { + buf_stdout.read_to_string(&mut output).unwrap(); + drop(buf_stdout); + } + + if let Ok(mut buf_stderr) = buf_stderr { + buf_stderr.read_to_string(&mut output).unwrap(); + drop(buf_stderr); + } if cfg!(windows) { // In windows output error and warning path files start with \\?\ @@ -76,6 +82,7 @@ pub(crate) async fn deploy_contract(file_name: &str, run_config: &RunConfig) -> true => BuildProfile::RELEASE.to_string(), false => BuildProfile::DEBUG.to_string(), }, + experimental_new_encoding: run_config.experimental.new_encoding, ..Default::default() }) .await @@ -118,14 +125,14 @@ pub(crate) async fn runs_on_node( }, contract: Some(contracts), signing_key: Some(SecretKey::from_str(SECRET_KEY).unwrap()), + experimental_new_encoding: run_config.experimental.new_encoding, ..Default::default() }; run(command).await.map(|ran_scripts| { ran_scripts .into_iter() - .next() - .map(|ran_script| ran_script.receipts) - .unwrap() + .flat_map(|ran_script| ran_script.receipts) + .collect::>() }) }) .await @@ -258,6 +265,15 @@ pub(crate) async fn compile_to_bytes(file_name: &str, run_config: &RunConfig) -> build_target: run_config.build_target, build_profile: BuildProfile::DEBUG.into(), release: run_config.release, + print: PrintOpts { + ast: false, + dca_graph: None, + dca_graph_url_format: None, + finalized_asm: false, + intermediate_asm: false, + ir: false, + reverse_order: false, + }, pkg: forc_pkg::PkgOpts { path: Some(format!( "{manifest_dir}/src/e2e_vm_tests/test_programs/{file_name}", @@ -329,17 +345,36 @@ pub(crate) async fn compile_and_run_unit_tests( .await } -pub(crate) fn test_json_abi(file_name: &str, built_package: &BuiltPackage) -> Result<()> { +pub(crate) fn test_json_abi( + file_name: &str, + built_package: &BuiltPackage, + experimental_new_encoding: bool, + update_output_files: bool, +) -> Result<()> { emit_json_abi(file_name, built_package)?; let manifest_dir = env!("CARGO_MANIFEST_DIR"); - let oracle_path = format!( - "{}/src/e2e_vm_tests/test_programs/{}/{}", - manifest_dir, file_name, "json_abi_oracle.json" - ); + let oracle_path = if experimental_new_encoding { + format!( + "{}/src/e2e_vm_tests/test_programs/{}/{}", + manifest_dir, file_name, "json_abi_oracle_new_encoding.json" + ) + } else { + format!( + "{}/src/e2e_vm_tests/test_programs/{}/{}", + manifest_dir, file_name, "json_abi_oracle.json" + ) + }; + let output_path = format!( "{}/src/e2e_vm_tests/test_programs/{}/{}", manifest_dir, file_name, "json_abi_output.json" ); + + // Update the oracle failing silently + if update_output_files { + let _ = std::fs::copy(&output_path, &oracle_path); + } + if fs::metadata(oracle_path.clone()).is_err() { bail!("JSON ABI oracle file does not exist for this test."); } @@ -347,11 +382,11 @@ pub(crate) fn test_json_abi(file_name: &str, built_package: &BuiltPackage) -> Re bail!("JSON ABI output file does not exist for this test."); } let oracle_contents = - fs::read_to_string(oracle_path).expect("Something went wrong reading the file."); + fs::read_to_string(&oracle_path).expect("Something went wrong reading the file."); let output_contents = - fs::read_to_string(output_path).expect("Something went wrong reading the file."); + fs::read_to_string(&output_path).expect("Something went wrong reading the file."); if oracle_contents != output_contents { - println!("Mismatched ABI JSON output."); + println!("Mismatched ABI JSON output [{oracle_path}] versus [{output_path}]",); println!( "{}", prettydiff::diff_lines(&oracle_contents, &output_contents) diff --git a/test/src/e2e_vm_tests/mod.rs b/test/src/e2e_vm_tests/mod.rs index 3133bce78f7..738e8b4dd94 100644 --- a/test/src/e2e_vm_tests/mod.rs +++ b/test/src/e2e_vm_tests/mod.rs @@ -7,7 +7,6 @@ use crate::e2e_vm_tests::harness::run_and_capture_output; use crate::{FilterConfig, RunConfig}; use anyhow::{anyhow, bail, Result}; -use assert_matches::assert_matches; use colored::*; use core::fmt; use forc_pkg::BuildProfile; @@ -29,7 +28,7 @@ use tracing::Instrument; use self::util::VecExt; -#[derive(PartialEq, Debug)] +#[derive(Clone, PartialEq, Debug)] enum TestCategory { Compiles, FailsToCompile, @@ -39,7 +38,7 @@ enum TestCategory { Disabled, } -#[derive(PartialEq)] +#[derive(Clone, PartialEq)] enum TestResult { Result(Word), Return(u64), @@ -58,25 +57,56 @@ impl fmt::Debug for TestResult { } } +#[derive(Clone)] +pub struct FileCheck(String); + +impl FileCheck { + pub fn build(&self) -> Result { + const DIRECTIVE_RX: &str = r"(?m)^\s*#\s*(\w+):\s+(.*)$"; + + let mut checker = filecheck::CheckerBuilder::new(); + + // Parse the file and check for unknown FileCheck directives. + let re = Regex::new(DIRECTIVE_RX).unwrap(); + for cap in re.captures_iter(&self.0) { + if let Ok(false) = checker.directive(&cap[0]) { + bail!("Unknown FileCheck directive: {}", &cap[1]); + } + } + + Ok(checker.finish()) + } +} + +#[derive(Clone)] struct TestDescription { name: String, + suffix: Option, category: TestCategory, script_data: Option>, + script_data_new_encoding: Option>, witness_data: Option>>, expected_result: Option, + expected_result_new_encoding: Option, expected_warnings: u32, contract_paths: Vec, validate_abi: bool, validate_storage_slots: bool, supported_targets: HashSet, unsupported_profiles: Vec<&'static str>, - checker: filecheck::Checker, + checker: FileCheck, + run_config: RunConfig, +} + +#[derive(PartialEq, Eq, Hash)] +struct DeployedContractKey { + pub contract_path: String, + pub new_encoding: bool, } #[derive(Clone)] struct TestContext { - run_config: RunConfig, - deployed_contracts: Arc>>, + deployed_contracts: Arc>>, } fn print_receipts(output: &mut String, receipts: &[Receipt]) { @@ -208,52 +238,64 @@ fn print_receipts(output: &mut String, receipts: &[Receipt]) { } impl TestContext { - async fn deploy_contract(&self, contract_path: String) -> Result { + async fn deploy_contract( + &self, + run_config: &RunConfig, + contract_path: String, + ) -> Result { + let key = DeployedContractKey { + contract_path: contract_path.clone(), + new_encoding: run_config.experimental.new_encoding, + }; + let mut deployed_contracts = self.deployed_contracts.lock().await; - Ok( - if let Some(contract_id) = deployed_contracts.get(&contract_path) { - *contract_id - } else { - let contract_id = - harness::deploy_contract(contract_path.as_str(), &self.run_config).await?; - deployed_contracts.insert(contract_path, contract_id); - contract_id - }, - ) + Ok(if let Some(contract_id) = deployed_contracts.get(&key) { + *contract_id + } else { + let contract_id = harness::deploy_contract(contract_path.as_str(), run_config).await?; + deployed_contracts.insert(key, contract_id); + contract_id + }) } + async fn run(&self, test: TestDescription, output: &mut String, verbose: bool) -> Result<()> { - let context = self; let TestDescription { name, category, script_data, + script_data_new_encoding, witness_data, expected_result, + expected_result_new_encoding, expected_warnings, contract_paths, validate_abi, validate_storage_slots, checker, + run_config, .. } = test; + let checker = checker.build().unwrap(); + + let script_data = if run_config.experimental.new_encoding { + script_data_new_encoding + } else { + script_data + }; + + let expected_result = if run_config.experimental.new_encoding { + expected_result_new_encoding + } else { + expected_result + }; + match category { TestCategory::Runs => { - let res = match expected_result { - Some(TestResult::Return(_)) - | Some(TestResult::ReturnData(_)) - | Some(TestResult::Revert(_)) => expected_result.unwrap(), - - _ => panic!( - "For {name}:\n\ - Invalid expected result for a 'runs' test: {expected_result:?}." - ), - }; + let expected_result = expected_result.unwrap(); - let (result, out) = run_and_capture_output(|| { - harness::compile_to_bytes(&name, &context.run_config) - }) - .await; + let (result, out) = + run_and_capture_output(|| harness::compile_to_bytes(&name, &run_config)).await; *output = out; let compiled = result?; @@ -273,7 +315,7 @@ impl TestContext { } let result = harness::runs_in_vm(compiled.clone(), script_data, witness_data)?; - let result = match result { + let actual_result = match result { harness::VMExecutionResult::Fuel(state, receipts) => { print_receipts(output, &receipts); match state { @@ -316,14 +358,19 @@ impl TestContext { } }; - if result != res { + if actual_result != expected_result { Err(anyhow::Error::msg(format!( - "expected: {res:?}\nactual: {result:?}" + "expected: {expected_result:?}\nactual: {actual_result:?}" ))) } else { if validate_abi { let (result, out) = run_and_capture_output(|| async { - harness::test_json_abi(&name, &compiled) + harness::test_json_abi( + &name, + &compiled, + run_config.experimental.new_encoding, + run_config.update_output_files, + ) }) .await; output.push_str(&out); @@ -334,10 +381,8 @@ impl TestContext { } TestCategory::Compiles => { - let (result, out) = run_and_capture_output(|| { - harness::compile_to_bytes(&name, &context.run_config) - }) - .await; + let (result, out) = + run_and_capture_output(|| harness::compile_to_bytes(&name, &run_config)).await; *output = out; let compiled_pkgs = match result? { @@ -366,7 +411,12 @@ impl TestContext { if validate_abi { for (name, built_pkg) in &compiled_pkgs { let (result, out) = run_and_capture_output(|| async { - harness::test_json_abi(name, built_pkg) + harness::test_json_abi( + name, + built_pkg, + run_config.experimental.new_encoding, + run_config.update_output_files, + ) }) .await; result?; @@ -388,10 +438,8 @@ impl TestContext { } TestCategory::FailsToCompile => { - let (result, out) = run_and_capture_output(|| { - harness::compile_to_bytes(&name, &context.run_config) - }) - .await; + let (result, out) = + run_and_capture_output(|| harness::compile_to_bytes(&name, &run_config)).await; *output = out; if result.is_ok() { @@ -403,15 +451,6 @@ impl TestContext { } TestCategory::RunsWithContract => { - let val = if let Some(TestResult::Result(val)) = expected_result { - val - } else { - panic!( - "For {name}:\nExpecting a 'result' action for a 'run_on_node' test, \ - found: {expected_result:?}." - ) - }; - if contract_paths.is_empty() { panic!( "For {name}\n\ @@ -422,19 +461,25 @@ impl TestContext { let mut contract_ids = Vec::new(); for contract_path in contract_paths.clone() { let (result, out) = run_and_capture_output(|| async { - context.deploy_contract(contract_path).await + self.deploy_contract(&run_config, contract_path).await }) .await; output.push_str(&out); contract_ids.push(result); } let contract_ids = contract_ids.into_iter().collect::, _>>()?; - let (result, out) = - harness::runs_on_node(&name, &context.run_config, &contract_ids).await; + + let (result, out) = harness::runs_on_node(&name, &run_config, &contract_ids).await; + output.push_str(&out); - let receipt = result?; - if !receipt.iter().all(|res| { + let receipts = result?; + + if verbose { + print_receipts(output, &receipts); + } + + if !receipts.iter().all(|res| { !matches!( res, fuel_tx::Receipt::Revert { .. } | fuel_tx::Receipt::Panic { .. } @@ -444,18 +489,47 @@ impl TestContext { for cid in contract_ids { println!("Deployed contract: 0x{cid}"); } - panic!("Receipts contain reverts or panics: {receipt:?}"); + + return Err(anyhow::Error::msg("Receipts contain reverts or panics")); } - assert!(receipt.len() >= 2); - assert_matches!(receipt[receipt.len() - 2], fuel_tx::Receipt::Return { .. }); - assert_eq!(receipt[receipt.len() - 2].val().unwrap(), val); + + if receipts.len() < 2 { + return Err(anyhow::Error::msg(format!( + "less than 2 receipts: {:?} receipts", + receipts.len() + ))); + } + + match &receipts[receipts.len() - 2] { + Receipt::Return { val, .. } => match expected_result.unwrap() { + TestResult::Result(v) => { + if v != *val { + return Err(anyhow::Error::msg(format!( + "return value does not match expected: {v:?}, {val:?}" + ))); + } + } + _ => todo!(), + }, + Receipt::ReturnData { data, .. } => match expected_result.unwrap() { + TestResult::ReturnData(v) => { + if v != *data.as_ref().unwrap() { + return Err(anyhow::Error::msg(format!( + "return value does not match expected: {v:?}, {data:?}" + ))); + } + } + _ => todo!(), + }, + _ => {} + }; Ok(()) } TestCategory::UnitTestsPass => { let (result, out) = - harness::compile_and_run_unit_tests(&name, &context.run_config, true).await; + harness::compile_and_run_unit_tests(&name, &run_config, true).await; *output = out; result.map(|tested_pkgs| { @@ -501,7 +575,7 @@ impl TestContext { pub async fn run(filter_config: &FilterConfig, run_config: &RunConfig) -> Result<()> { // Discover tests - let mut tests = discover_test_configs()?; + let mut tests = discover_test_configs(run_config)?; let total_number_of_tests = tests.len(); // Filter tests @@ -541,16 +615,39 @@ pub async fn run(filter_config: &FilterConfig, run_config: &RunConfig) -> Result if filter_config.first_only && !tests.is_empty() { tests = vec![tests.remove(0)]; } - let cur_profile = if run_config.release { - BuildProfile::RELEASE - } else { - BuildProfile::DEBUG - }; - tests.retain(|t| !t.unsupported_profiles.contains(&cur_profile)); + + // Expand tests that need to run with multiple configurations. + // Be mindful that this can explode exponentially the number of tests + // that run because one expansion expands on top of another + let mut tests = tests; + let expansions = ["new_encoding"]; + for expansion in expansions { + tests = tests + .into_iter() + .flat_map(|t| { + let has_script_data_new_encoding = t.script_data_new_encoding.is_some(); + let has_contracts = !t.contract_paths.is_empty(); + let has_expected_return = t.expected_result_new_encoding.is_some(); + if expansion == "new_encoding" + && (has_script_data_new_encoding || has_contracts || has_expected_return) + { + let mut with_new_encoding = t.clone(); + with_new_encoding.suffix = Some("New Encoding".into()); + + let mut run_config_with_new_encoding = run_config.clone(); + run_config_with_new_encoding.experimental.new_encoding = true; + with_new_encoding.run_config = run_config_with_new_encoding; + + vec![t, with_new_encoding] + } else { + vec![t] + } + }) + .collect(); + } // Run tests let context = TestContext { - run_config: run_config.clone(), deployed_contracts: Default::default(), }; let mut number_of_tests_executed = 0; @@ -558,7 +655,22 @@ pub async fn run(filter_config: &FilterConfig, run_config: &RunConfig) -> Result let mut failed_tests = vec![]; for (i, test) in tests.into_iter().enumerate() { - let name = test.name.clone(); + let cur_profile = if run_config.release { + BuildProfile::RELEASE + } else { + BuildProfile::DEBUG + }; + + if test.unsupported_profiles.contains(&cur_profile) { + continue; + } + + let name = if let Some(suffix) = test.suffix.as_ref() { + format!("{} ({})", test.name, suffix) + } else { + test.name.clone() + }; + print!("Testing {} ...", name.clone().bold()); stdout().flush().unwrap(); @@ -601,21 +713,21 @@ pub async fn run(filter_config: &FilterConfig, run_config: &RunConfig) -> Result if number_of_tests_executed == 0 { if let Some(skip_until) = &filter_config.skip_until { tracing::info!( - "Filtered {} tests with `skip-until` regex: {}", + "Filtered {} tests with `skip-until` regex: {:?}", skipped_tests.len(), skip_until.to_string() ); } if let Some(include) = &filter_config.include { tracing::info!( - "Filtered {} tests with `include` regex: {}", + "Filtered {} tests with `include` regex: {:?}", included_tests.len(), include.to_string() ); } if let Some(exclude) = &filter_config.exclude { tracing::info!( - "Filtered {} tests with `exclude` regex: {}", + "Filtered {} tests with `exclude` regex: {:?}", excluded_tests.len(), exclude.to_string() ); @@ -660,8 +772,12 @@ pub async fn run(filter_config: &FilterConfig, run_config: &RunConfig) -> Result } } -fn discover_test_configs() -> Result> { - fn recursive_search(path: &Path, configs: &mut Vec) -> Result<()> { +fn discover_test_configs(run_config: &RunConfig) -> Result> { + fn recursive_search( + path: &Path, + run_config: &RunConfig, + configs: &mut Vec, + ) -> Result<()> { let wrap_err = |e| { let relative_path = path .iter() @@ -672,10 +788,10 @@ fn discover_test_configs() -> Result> { }; if path.is_dir() { for entry in std::fs::read_dir(path).unwrap() { - recursive_search(&entry.unwrap().path(), configs)?; + recursive_search(&entry.unwrap().path(), run_config, configs)?; } } else if path.is_file() && path.file_name().map(|f| f == "test.toml").unwrap_or(false) { - configs.push(parse_test_toml(path).map_err(wrap_err)?); + configs.push(parse_test_toml(path, run_config).map_err(wrap_err)?); } Ok(()) } @@ -684,26 +800,10 @@ fn discover_test_configs() -> Result> { let tests_root_dir = format!("{manifest_dir}/src/e2e_vm_tests/test_programs"); let mut configs = Vec::new(); - recursive_search(&PathBuf::from(tests_root_dir), &mut configs)?; + recursive_search(&PathBuf::from(tests_root_dir), run_config, &mut configs)?; Ok(configs) } -const DIRECTIVE_RX: &str = r"(?m)^\s*#\s*(\w+):\s+(.*)$"; - -fn build_file_checker(content: &str) -> Result { - let mut checker = filecheck::CheckerBuilder::new(); - - // Parse the file and check for unknown FileCheck directives. - let re = Regex::new(DIRECTIVE_RX).unwrap(); - for cap in re.captures_iter(content) { - if let Ok(false) = checker.directive(&cap[0]) { - bail!("Unknown FileCheck directive: {}", &cap[1]); - } - } - - Ok(checker.finish()) -} - /// This functions gets passed the previously built FileCheck-based file checker, /// along with the output of the compilation, and checks the output for the /// FileCheck directives that were found in the test.toml file, panicking @@ -720,10 +820,11 @@ fn check_file_checker(checker: filecheck::Checker, name: &String, output: &str) } } -fn parse_test_toml(path: &Path) -> Result { +fn parse_test_toml(path: &Path, run_config: &RunConfig) -> Result { let toml_content_str = std::fs::read_to_string(path)?; - let checker = build_file_checker(&toml_content_str)?; + let file_check = FileCheck(toml_content_str.clone()); + let checker = file_check.build()?; let toml_content = toml_content_str.parse::()?; @@ -752,11 +853,11 @@ fn parse_test_toml(path: &Path) -> Result { bail!("'fail' tests must contain some FileCheck verification directives."); } - let script_data = match &category { + let (script_data, script_data_new_encoding) = match &category { TestCategory::Runs | TestCategory::RunsWithContract => { - match toml_content.get("script_data") { + let script_data = match toml_content.get("script_data") { Some(toml::Value::String(v)) => { - let decoded = hex::decode(v) + let decoded = hex::decode(v.replace(' ', "")) .map_err(|e| anyhow!("Invalid hex value for 'script_data': {}", e))?; Some(decoded) } @@ -764,12 +865,26 @@ fn parse_test_toml(path: &Path) -> Result { bail!("Expected 'script_data' to be a hex string."); } _ => None, - } + }; + + let script_data_new_encoding = match toml_content.get("script_data_new_encoding") { + Some(toml::Value::String(v)) => { + let decoded = hex::decode(v.replace(' ', "")) + .map_err(|e| anyhow!("Invalid hex value for 'script_data': {}", e))?; + Some(decoded) + } + Some(_) => { + bail!("Expected 'script_data' to be a hex string."); + } + _ => None, + }; + + (script_data, script_data_new_encoding) } TestCategory::Compiles | TestCategory::FailsToCompile | TestCategory::UnitTestsPass - | TestCategory::Disabled => None, + | TestCategory::Disabled => (None, None), }; let witness_data = match &category { @@ -806,7 +921,7 @@ fn parse_test_toml(path: &Path) -> Result { let expected_result = match &category { TestCategory::Runs | TestCategory::RunsWithContract => { - Some(get_expected_result(&toml_content)?) + Some(get_expected_result("expected_result", &toml_content)?) } TestCategory::Compiles | TestCategory::FailsToCompile @@ -814,6 +929,14 @@ fn parse_test_toml(path: &Path) -> Result { | TestCategory::Disabled => None, }; + let expected_result_new_encoding = match ( + &category, + get_expected_result("expected_result_new_encoding", &toml_content), + ) { + (TestCategory::Runs | TestCategory::RunsWithContract, Ok(value)) => Some(value), + _ => None, + }; + let contract_paths = match toml_content.get("contracts") { None => Vec::new(), Some(contracts) => contracts @@ -891,17 +1014,21 @@ fn parse_test_toml(path: &Path) -> Result { Ok(TestDescription { name, + suffix: None, category, script_data, + script_data_new_encoding, witness_data, expected_result, + expected_result_new_encoding, expected_warnings, contract_paths, validate_abi, validate_storage_slots, supported_targets, unsupported_profiles, - checker, + checker: file_check, + run_config: run_config.clone(), }) } @@ -926,7 +1053,7 @@ fn get_build_profile_from_value(value: &toml::Value) -> Result<&'static str> { } } -fn get_expected_result(toml_content: &toml::Value) -> Result { +fn get_expected_result(key: &str, toml_content: &toml::Value) -> Result { fn get_action_value(action: &toml::Value, expected_value: &toml::Value) -> Result { match (action.as_str(), expected_value) { // A simple integer value. @@ -948,7 +1075,7 @@ fn get_expected_result(toml_content: &toml::Value) -> Result { } toml_content - .get("expected_result") + .get(key) .ok_or_else(|| anyhow!( "Could not find mandatory 'expected_result' entry.")) .and_then(|expected_result_table| { expected_result_table diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/const-instead-of-let/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/const-instead-of-let/test.toml index 13a9b5c552b..ff039fdfc16 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/const-instead-of-let/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/const-instead-of-let/test.toml @@ -5,4 +5,4 @@ category = "fail" # check: $()const INVALID_CONST = contract_1.foo(); # nextln: $()Could not evaluate initializer to a const declaration. -# check: $()Aborting due to 1 error \ No newline at end of file +# check: $()Aborting due to 1 error diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/Forc.lock index 17c24630366..6066710fa63 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/Forc.lock @@ -1,8 +1,16 @@ [[package]] -name = 'core' -source = 'path+from-root-EE00857339AC041F' +name = "core" +source = "path+from-root-EE00857339AC041F" [[package]] -name = 'main_args_copy' -source = 'member' -dependencies = ['core'] +name = "main_args_copy" +source = "member" +dependencies = [ + "core", + "std", +] + +[[package]] +name = "std" +source = "path+from-root-EE00857339AC041F" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/Forc.toml index 7314cf77840..146f55f2d44 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/Forc.toml @@ -3,7 +3,7 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" name = "main_args_copy" -implicit-std = false [dependencies] core = { path = "../../../../../../../../sway-lib-core" } +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/json_abi_oracle_new_encoding.json new file mode 100644 index 00000000000..fd53929d11d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/json_abi_oracle_new_encoding.json @@ -0,0 +1,26 @@ +{ + "configurables": [], + "encoding": "1", + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "__entry", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "raw untyped slice", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/test.toml index cd63114a628..231114350c6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy/test.toml @@ -1,4 +1,10 @@ category = "run" -script_data = "00000000000005380000000000000001" # (1336, 1) + +# 1336 encoded as [0, 0, 0, 0, 0, 0, 5, 56] +script_data = "0000000000000538" expected_result = { action = "return", value = 1337 } + +script_data_new_encoding = "0000000000000538" +expected_result_new_encoding = { action = "return_data", value = "0000000000000539" } + validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy_copy/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy_copy/json_abi_oracle_new_encoding.json new file mode 100644 index 00000000000..fd53929d11d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy_copy/json_abi_oracle_new_encoding.json @@ -0,0 +1,26 @@ +{ + "configurables": [], + "encoding": "1", + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "__entry", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "raw untyped slice", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy_copy/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy_copy/test.toml index cd63114a628..7b398f8ba64 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy_copy/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_copy_copy/test.toml @@ -1,4 +1,7 @@ category = "run" -script_data = "00000000000005380000000000000001" # (1336, 1) +# (1336, 1) +script_data = "0000000000000538 0000000000000001" +script_data_new_encoding = "0000000000000538 0000000000000001" expected_result = { action = "return", value = 1337 } +expected_result_new_encoding = { action = "return_data", value = "0000000000000539" } validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/Forc.lock index dee7d69d3c4..ae0b07ad373 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/Forc.lock @@ -1,8 +1,16 @@ [[package]] -name = 'core' -source = 'path+from-root-66C7F3C6EA70992E' +name = "core" +source = "path+from-root-66C7F3C6EA70992E" [[package]] -name = 'main_args_empty' -source = 'member' -dependencies = ['core'] +name = "main_args_empty" +source = "member" +dependencies = [ + "core", + "std", +] + +[[package]] +name = "std" +source = "path+from-root-66C7F3C6EA70992E" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/Forc.toml index 3df62d8e6a2..0df387531fc 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/Forc.toml @@ -3,7 +3,7 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" name = "main_args_empty" -implicit-std = false [dependencies] core = { path = "../../../../../../../../sway-lib-core" } +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/json_abi_oracle_new_encoding.json new file mode 100644 index 00000000000..fd53929d11d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/json_abi_oracle_new_encoding.json @@ -0,0 +1,26 @@ +{ + "configurables": [], + "encoding": "1", + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "__entry", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "raw untyped slice", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/test.toml index cd63114a628..1074072af31 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_empty/test.toml @@ -1,4 +1,9 @@ category = "run" -script_data = "00000000000005380000000000000001" # (1336, 1) +# (1336, 1) +script_data = "0000000000000538 0000000000000001" expected_result = { action = "return", value = 1337 } + +script_data_new_encoding = "0000000000000538 0000000000000001" +expected_result_new_encoding = { action = "return_data", value = "0000000000000539" } + validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_predicate/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_predicate/test.toml index 17f1d4bf176..f35894d5349 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_predicate/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_predicate/test.toml @@ -1,4 +1,6 @@ category = "disabled" -script_data = "00000000000005380000000000000001" # (1336, 1) +# (1336, 1) +script_data = "0000000000000538 0000000000000001" +script_data_new_encoding = "0000000000000538 0000000000000001" expected_result = { action = "return", value = 1 } validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref/json_abi_oracle_new_encoding.json new file mode 100644 index 00000000000..fd53929d11d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref/json_abi_oracle_new_encoding.json @@ -0,0 +1,26 @@ +{ + "configurables": [], + "encoding": "1", + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "__entry", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "raw untyped slice", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref/test.toml index cd63114a628..7151747728b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref/test.toml @@ -1,4 +1,10 @@ category = "run" -script_data = "00000000000005380000000000000001" # (1336, 1) + +# (1336, 1) +script_data = "0000000000000538 0000000000000001" expected_result = { action = "return", value = 1337 } + +script_data_new_encoding = "0000000000000538 0000000000000001" +expected_result_new_encoding = { action = "return_data", value = "0000000000000539" } + validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_copy/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_copy/json_abi_oracle_new_encoding.json new file mode 100644 index 00000000000..fd53929d11d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_copy/json_abi_oracle_new_encoding.json @@ -0,0 +1,26 @@ +{ + "configurables": [], + "encoding": "1", + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "__entry", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "raw untyped slice", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_copy/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_copy/test.toml index cd63114a628..1074072af31 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_copy/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_copy/test.toml @@ -1,4 +1,9 @@ category = "run" -script_data = "00000000000005380000000000000001" # (1336, 1) +# (1336, 1) +script_data = "0000000000000538 0000000000000001" expected_result = { action = "return", value = 1337 } + +script_data_new_encoding = "0000000000000538 0000000000000001" +expected_result_new_encoding = { action = "return_data", value = "0000000000000539" } + validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_ref/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_ref/json_abi_oracle_new_encoding.json new file mode 100644 index 00000000000..fd53929d11d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_ref/json_abi_oracle_new_encoding.json @@ -0,0 +1,26 @@ +{ + "configurables": [], + "encoding": "1", + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "__entry", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "raw untyped slice", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_ref/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_ref/test.toml index cd63114a628..1074072af31 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_ref/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_ref_ref/test.toml @@ -1,4 +1,9 @@ category = "run" -script_data = "00000000000005380000000000000001" # (1336, 1) +# (1336, 1) +script_data = "0000000000000538 0000000000000001" expected_result = { action = "return", value = 1337 } + +script_data_new_encoding = "0000000000000538 0000000000000001" +expected_result_new_encoding = { action = "return_data", value = "0000000000000539" } + validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle.json index 550857d0a7b..ca8991fbf65 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle.json @@ -18,7 +18,16 @@ } } ], - "loggedTypes": [], + "loggedTypes": [ + { + "logId": 0, + "loggedType": { + "name": "", + "type": 1, + "typeArguments": null + } + } + ], "messagesTypes": [], "types": [ { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle_new_encoding.json new file mode 100644 index 00000000000..d5959d460ac --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle_new_encoding.json @@ -0,0 +1,105 @@ +{ + "configurables": [], + "encoding": "1", + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "__entry", + "output": { + "name": "", + "type": 3, + "typeArguments": null + } + } + ], + "loggedTypes": [ + { + "logId": 0, + "loggedType": { + "name": "", + "type": 1, + "typeArguments": null + } + } + ], + "messagesTypes": [], + "types": [ + { + "components": [ + { + "name": "__tuple_element", + "type": 5, + "typeArguments": null + }, + { + "name": "__tuple_element", + "type": 2, + "typeArguments": null + } + ], + "type": "(_, _)", + "typeId": 0, + "typeParameters": null + }, + { + "components": [ + { + "name": "__array_element", + "type": 0, + "typeArguments": null + } + ], + "type": "[_; 2]", + "typeId": 1, + "typeParameters": null + }, + { + "components": [ + { + "name": "Positive", + "type": 6, + "typeArguments": null + }, + { + "name": "Negative", + "type": 6, + "typeArguments": null + } + ], + "type": "enum SignedNum", + "typeId": 2, + "typeParameters": null + }, + { + "components": null, + "type": "raw untyped slice", + "typeId": 3, + "typeParameters": null + }, + { + "components": null, + "type": "str[3]", + "typeId": 4, + "typeParameters": null + }, + { + "components": [ + { + "name": "val", + "type": 4, + "typeArguments": null + } + ], + "type": "struct OpName", + "typeId": 5, + "typeParameters": null + }, + { + "components": null, + "type": "u64", + "typeId": 6, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/main.sw index f1167fc5a1f..cf8cb142ee1 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/main.sw @@ -18,6 +18,7 @@ struct OpName { } fn main(ops: [(OpName, SignedNum); 2]) -> u64 { + __log(ops); assert(eq_str_3(ops[0].0.val, "set")); assert(match ops[0].1 { SignedNum::Positive(n) => n, diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/test.toml index 56fcc72c7be..3e2f3fe50c5 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/test.toml @@ -1,5 +1,10 @@ category = "run" -script_data = "73657400000000000000000000000000000000000000053a616464000000000000000000000000010000000000000001" # [("set", SignedNum::Positive(1338)), ("add", SignedNum::Negative(1))] +# [("set", SignedNum::Positive(1338)), ("add", SignedNum::Negative(1))] +script_data = "73657400000000000000000000000000000000000000053a616464000000000000000000000000010000000000000001" expected_result = { action = "return", value = 1 } + +script_data_new_encoding = "736574 0000000000000000 000000000000053a 616464 0000000000000001 0000000000000001" +expected_result_new_encoding = { action = "return_data", value = "0000000000000001" } + validate_abi = true -expected_warnings = 4 +expected_warnings = 7 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/src/main.sw index 0593601061f..fd524024ea0 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/trait_nested/src/main.sw @@ -32,12 +32,6 @@ impl Eq for (u64,) { } } -impl AbiEncode for (u64, ) { - fn abi_encode(self, ref mut buffer: Buffer) { - buffer.push(self.0); - } -} - fn main() -> bool { assert_eq(f::<(u64, )>(), (42,)); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/payable_non_zero_coins/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/payable_non_zero_coins/test.toml index b490ce52607..829ccebf6e8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/payable_non_zero_coins/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/payable_non_zero_coins/test.toml @@ -1,3 +1,5 @@ category = "compile" +expected_warnings = 0 +experimental_new_encoding = true # not: $()Possibly non-zero amount of coins transferred to non-payable contract method "send_funds". diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/Forc.lock index a807626fdae..06a92f56d02 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/Forc.lock @@ -1,20 +1,25 @@ [[package]] -name = 'array_of_structs_abi' -source = 'path+from-root-40616FC980A839AE' +name = "array_of_structs_abi" +source = "path+from-root-40616FC980A839AE" +dependencies = [ + "core", + "std", +] [[package]] -name = 'array_of_structs_caller' -source = 'member' +name = "array_of_structs_caller" +source = "member" dependencies = [ - 'array_of_structs_abi', - 'std', + "array_of_structs_abi", + "core", + "std", ] [[package]] -name = 'core' -source = 'path+from-root-40616FC980A839AE' +name = "core" +source = "path+from-root-40616FC980A839AE" [[package]] -name = 'std' -source = 'path+from-root-40616FC980A839AE' -dependencies = ['core'] +name = "std" +source = "path+from-root-40616FC980A839AE" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/Forc.toml index 277f55d1f6f..fa675ba7838 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/Forc.toml @@ -6,4 +6,5 @@ name = "array_of_structs_caller" [dependencies] array_of_structs_abi = { path = "../../test_abis/array_of_structs_abi" } +core = { path = "../../../../../../../sway-lib-core" } std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw index a77658c74fb..bd48bf5a4fe 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw @@ -3,8 +3,13 @@ script; use array_of_structs_abi::{Id, TestContract, Wrapper}; use std::hash::*; +#[cfg(experimental_new_encoding = false)] +const CONTRACT_ID = 0xe2a4f86301f8b57ff2c93ce68366669fc2f0926dccd26f9f6550b049cb324a2c; +#[cfg(experimental_new_encoding = true)] +const CONTRACT_ID = 0x18912cbce488c8786f2f6ccf7e1e0cab6341f025f3fe2ecb053de11b93ba9ee8; + fn main() -> u64 { - let addr = abi(TestContract, 0xe2a4f86301f8b57ff2c93ce68366669fc2f0926dccd26f9f6550b049cb324a2c); + let addr = abi(TestContract, CONTRACT_ID); let input = [Wrapper { id: Id { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/test.toml index 7e1704675f7..f4354b48006 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/test.toml @@ -1,4 +1,5 @@ category = "run_on_node" expected_result = { action = "result", value = 1 } +expected_result_new_encoding = { action = "return_data", value = "0000000000000001" } contracts = ["should_pass/test_contracts/array_of_structs_contract"] unsupported_profiles = ["debug"] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw index 3052b722be6..bb213e621a8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw @@ -6,15 +6,25 @@ use std::contract_id::*; use std::constants::DEFAULT_SUB_ID; use test_fuel_coin_abi::*; +#[cfg(experimental_new_encoding = false)] +const FUEL_COIN_CONTRACT_ID = 0x542c6e67e5e8768a2c119a80ddcbd1f8d01110ced16fda37e4aa77ebb6d6cdb9; +#[cfg(experimental_new_encoding = true)] +const FUEL_COIN_CONTRACT_ID = 0x819fafa79acf18c418188f02ebd7eb20c03597a9b986bb73284df6b4d501c86f; + +#[cfg(experimental_new_encoding = false)] +const BALANCE_CONTRACT_ID = 0xe50966cd6b1da8fe006e3e876e08f3df6948ce426e1a7cfe49fba411b0a11f89; +#[cfg(experimental_new_encoding = true)] +const BALANCE_CONTRACT_ID = 0x3fb29b6614aca92e5036d803e4e90578ac33812c4ff7a3eb6d1857d9e79b826b; + fn main() -> bool { let default_gas = 1_000_000_000_000; // the deployed fuel_coin Contract_Id: - let fuelcoin_id = ContractId::from(0x542c6e67e5e8768a2c119a80ddcbd1f8d01110ced16fda37e4aa77ebb6d6cdb9); + let fuelcoin_id = ContractId::from(FUEL_COIN_CONTRACT_ID); let fuelcoin_asset_id = AssetId::new(fuelcoin_id, DEFAULT_SUB_ID); // contract ID for sway/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/balance_test_contract/ - let balance_test_id = ContractId::from(0xe50966cd6b1da8fe006e3e876e08f3df6948ce426e1a7cfe49fba411b0a11f89); + let balance_test_id = ContractId::from(BALANCE_CONTRACT_ID); // todo: use correct type ContractId let fuel_coin = abi(TestFuelCoin, fuelcoin_id.into()); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/test.toml index 344b39978d8..a653725436b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/test.toml @@ -1,4 +1,5 @@ category = "run_on_node" expected_result = { action = "result", value = 1 } +expected_result_new_encoding = { action = "return_data", value = "01" } contracts = ["should_pass/test_contracts/balance_test_contract", "should_pass/test_contracts/test_fuel_coin_contract"] unsupported_profiles = ["debug"] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw index 57c3324c324..39497cabb87 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw @@ -3,17 +3,19 @@ script; use std::constants::BASE_ASSET_ID; use balance_test_abi::BalanceTest; -fn main() -> bool { - // @todo switch to using ContractId when abi signature changes. - let balance_test_contract_id = 0xe50966cd6b1da8fe006e3e876e08f3df6948ce426e1a7cfe49fba411b0a11f89; +#[cfg(experimental_new_encoding = false)] +const CONTRACT_ID = 0xe50966cd6b1da8fe006e3e876e08f3df6948ce426e1a7cfe49fba411b0a11f89; +#[cfg(experimental_new_encoding = true)] +const CONTRACT_ID = 0x3fb29b6614aca92e5036d803e4e90578ac33812c4ff7a3eb6d1857d9e79b826b; - let balance_test_contract = abi(BalanceTest, balance_test_contract_id); +fn main() -> bool { + let balance_test_contract = abi(BalanceTest, CONTRACT_ID); let number = balance_test_contract.get_42 { gas: u64::max() } (); - let balance = asm(asset_bal, asset: BASE_ASSET_ID, id: balance_test_contract_id) { + let balance = asm(asset_bal, asset: BASE_ASSET_ID, id: CONTRACT_ID) { bal asset_bal asset id; asset_bal: u64 }; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/test.toml index 4f5d0c8d484..6e8449c2dd3 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/test.toml @@ -1,4 +1,6 @@ category = "run_on_node" expected_result = { action = "result", value = 1 } +expected_result_new_encoding = { action = "return_data", value = "01" } contracts = ["should_pass/test_contracts/balance_test_contract"] -unsupported_profiles = ["debug"] \ No newline at end of file +unsupported_profiles = ["debug"] +extra_run_with_experimental_new_encoding = true \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw index 76383b8521a..04d56748792 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw @@ -2,8 +2,13 @@ script; use abi_with_tuples::*; +#[cfg(experimental_new_encoding = false)] +const CONTRACT_ID = 0x1200d031e9c10f8d9bd9dd556a98a0c88e74a4da991047556f78b1bcc1be2ab6; +#[cfg(experimental_new_encoding = true)] +const CONTRACT_ID = 0xa6f9dd4eb91fadf782b0a62924f09b798dd4d374f692bb91070caf098c0bc769; + fn main() -> bool { - let the_abi = abi(MyContract, 0x1200d031e9c10f8d9bd9dd556a98a0c88e74a4da991047556f78b1bcc1be2ab6); + let the_abi = abi(MyContract, CONTRACT_ID); let param1 = ( Person { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/test.toml index 6813119dff6..1bd873a6976 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/test.toml @@ -1,4 +1,5 @@ category = "run_on_node" expected_result = { action = "result", value = 1 } +expected_result_new_encoding = { action = "return_data", value = "01" } contracts = ["should_pass/test_contracts/abi_with_tuples_contract"] unsupported_profiles = ["debug"] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw index 0105fae4e0a..3111e924690 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw @@ -1,14 +1,17 @@ script; use basic_storage_abi::{BasicStorage, Quad}; +#[cfg(experimental_new_encoding = false)] +const CONTRACT_ID = 0xd956f6bb7ee577561325f16f51534c001061342972a0bef9c2dcfc6d83919491; +#[cfg(experimental_new_encoding = true)] +const CONTRACT_ID = 0x21c57ccaa695c1744898bc14753a7772d150640e8337f537d23e248a77bdb679; + fn main() -> u64 { - let addr = abi(BasicStorage, 0xd956f6bb7ee577561325f16f51534c001061342972a0bef9c2dcfc6d83919491); + let addr = abi(BasicStorage, CONTRACT_ID); let key = 0x0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; let value = 4242; /* Simple test using `store` and `get` from `std::storage */ - let res:Option = addr.get_u64(key); - assert(res.is_none()); // nothing to read just yet addr.store_u64(key, value); assert(addr.get_u64(key).unwrap() == value); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/test.toml index e917ac146de..82df22d8c1e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/test.toml @@ -1,4 +1,5 @@ category = "run_on_node" expected_result = { action = "result", value = 4242 } +expected_result_new_encoding = { action = "return_data", value = "0000000000001092" } contracts = ["should_pass/test_contracts/basic_storage"] unsupported_profiles = ["debug"] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw index 80d73638239..345cb2b4138 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw @@ -2,8 +2,13 @@ script; use contract_with_type_aliases_abi::*; +#[cfg(experimental_new_encoding = false)] +const CONTRACT_ID = 0xbd74e82536dd497dc73b8810ed5750b2b3b5b97a08d31e89b4135cb5360d447d; +#[cfg(experimental_new_encoding = true)] +const CONTRACT_ID = 0x694fb5392d964ff8fcf7f224870f7f60f43721a9770000317660702a3b0a30d8; + fn main() { - let caller = abi(MyContract, 0xbd74e82536dd497dc73b8810ed5750b2b3b5b97a08d31e89b4135cb5360d447d); + let caller = abi(MyContract, CONTRACT_ID); let x: b256 = 0x0101010101010101010101010101010101010101010101010101010101010101; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/test.toml index 48f8a744c9d..89f578140cb 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/test.toml @@ -1,4 +1,6 @@ category = "run_on_node" expected_result = { action = "result", value = 0 } +expected_result_new_encoding = { action = "return_data", value = "" } contracts = ["should_pass/test_contracts/contract_with_type_aliases"] -unsupported_profiles = ["debug"] \ No newline at end of file +unsupported_profiles = ["debug"] +extra_run_with_experimental_new_encoding = true \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw index fdbc8d6ebfd..1745668ee45 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw @@ -2,12 +2,25 @@ script; use increment_abi::Incrementor; +#[cfg(experimental_new_encoding = false)] +const CONTRACT_ID = 0xa1aa9555466ef3c61914e5426973e2257cb4dcd8311ffbbe0e8850a9742f312d; +#[cfg(experimental_new_encoding = true)] +const CONTRACT_ID = 0xfc785a275345b2344f3dafe03cc910d36691de6456e4d3277d5b2b0fe85479b2; + fn main() -> bool { - let the_abi = abi(Incrementor, 0xa1aa9555466ef3c61914e5426973e2257cb4dcd8311ffbbe0e8850a9742f312d); - let _ = the_abi.increment(5); - let _ = the_abi.increment(5); + let the_abi = abi(Incrementor, CONTRACT_ID); + + let initial = the_abi.get(); + + let result = the_abi.increment(5); + assert(result == initial + 5); + + let result = the_abi.increment(5); + assert(result == initial + 10); + let result = the_abi.get(); - assert(result == 10); + assert(result == initial + 10); + log(result); true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/test.toml index f20244c28b3..c4b555cc436 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/test.toml @@ -1,4 +1,6 @@ category = "run_on_node" expected_result = { action = "result", value = 1 } +expected_result_new_encoding = { action = "return_data", value = "01" } contracts = ["should_pass/test_contracts/increment_contract"] -unsupported_profiles = ["debug"] \ No newline at end of file +unsupported_profiles = ["debug"] +extra_run_with_experimental_new_encoding = true \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw index 5b619767541..293f9af3982 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw @@ -2,11 +2,13 @@ script; use storage_enum_abi::*; -fn main() -> u64 { - let contract_id = 0x039f59a5f7ab74f3c75eedaedeabdbff9b8bc5310f44ff10b0344fc316026e7d; - let caller = abi(StorageEnum, contract_id); +#[cfg(experimental_new_encoding = false)] +const CONTRACT_ID = 0x039f59a5f7ab74f3c75eedaedeabdbff9b8bc5310f44ff10b0344fc316026e7d; +#[cfg(experimental_new_encoding = true)] +const CONTRACT_ID = 0xc12257fb772806169eb2fa2322e68bc33e3c6b53a9942acd03bc837cae7abd66; +fn main() -> u64 { + let caller = abi(StorageEnum, CONTRACT_ID); let res = caller.read_write_enums(); - res } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/test.toml index 838cfe3151c..6187534a106 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/test.toml @@ -1,4 +1,6 @@ category = "run_on_node" expected_result = { action = "result", value = 171 } +expected_result_new_encoding = { action = "return_data", value = "00000000000000AB" } contracts = ["should_pass/test_contracts/storage_enum_contract"] -unsupported_profiles = ["debug"] \ No newline at end of file +unsupported_profiles = ["debug"] +extra_run_with_experimental_new_encoding = true \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw index 422fa8263dd..537039377dd 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw @@ -2,9 +2,14 @@ script; use auth_testing_abi::AuthTesting; +#[cfg(experimental_new_encoding = false)] +const CONTRACT_ID = 0x66d9f99ddeeff7d1c6d3b986afd5d20029860289cb74c64e30c255730966d24f; +#[cfg(experimental_new_encoding = true)] +const CONTRACT_ID = 0x90c6740cb228dd96a1b27c30070d67d4320843327cdae09a3f8ba4df30916eba; + // should be false in the case of a script fn main() -> bool { - let caller = abi(AuthTesting, 0x66d9f99ddeeff7d1c6d3b986afd5d20029860289cb74c64e30c255730966d24f); + let caller = abi(AuthTesting, CONTRACT_ID); let result = caller.returns_gm_one(); assert(result); result diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/test.toml index a1a48726421..b6d99958f89 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/test.toml @@ -1,4 +1,5 @@ category = "run_on_node" expected_result = { action = "result", value = 1 } +expected_result_new_encoding = { action = "return_data", value = "01" } contracts = ["should_pass/test_contracts/auth_testing_contract"] -unsupported_profiles = ["debug"] \ No newline at end of file +unsupported_profiles = ["debug"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw index ef9d8ef7049..6bae595ec53 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw @@ -1,12 +1,18 @@ script; +use core::codec::*; use std::constants::BASE_ASSET_ID; use context_testing_abi::*; +#[cfg(experimental_new_encoding = false)] +const CONTRACT_ID = 0x65dae4fedb02e2d70cdb56e2b82d23a2baa69a6acdbf01cc1271c7c1a1abe2cc; +#[cfg(experimental_new_encoding = true)] +const CONTRACT_ID = 0x441f75894772629af8addf3bac4b04f92800aa9e509b1a438f9c82d7f5dd7972; + fn main() -> bool { let gas: u64 = u64::max(); let amount: u64 = 11; - let other_contract_id = ContractId::from(0x65dae4fedb02e2d70cdb56e2b82d23a2baa69a6acdbf01cc1271c7c1a1abe2cc); + let other_contract_id = ContractId::from(CONTRACT_ID); let other_contract_id_b256: b256 = other_contract_id.into(); let base_asset_id = BASE_ASSET_ID; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/test.toml index fe4f2c19865..f0f93f5e2ed 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/test.toml @@ -1,4 +1,6 @@ category = "run_on_node" expected_result = { action = "result", value = 1 } +expected_result_new_encoding = { action = "return_data", value = "01" } contracts = ["should_pass/test_contracts/context_testing_contract"] -unsupported_profiles = ["debug"] \ No newline at end of file +unsupported_profiles = ["debug"] +expected_warnings = 1 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw index e9d88badfa2..d720e91b4c7 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw @@ -2,9 +2,13 @@ script; use nested_struct_args_abi::*; +#[cfg(experimental_new_encoding = false)] +const CONTRACT_ID = 0x0fd8fed83ef774a35708706495b49f93254cc5ded343c3bd4416a70c8eb47e01; +#[cfg(experimental_new_encoding = true)] +const CONTRACT_ID = 0x4db0b0649c279387dcb6e1b84ac83c3da1b806ab0f539233d4328c0598ed4a70; + fn main() -> bool { - let contract_id = 0x0fd8fed83ef774a35708706495b49f93254cc5ded343c3bd4416a70c8eb47e01; - let caller = abi(NestedStructArgs, contract_id); + let caller = abi(NestedStructArgs, CONTRACT_ID); let param_one = StructOne { inn: Inner { foo: 42 }, diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/test.toml index 90a8632cd73..d21f0326016 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/test.toml @@ -1,4 +1,5 @@ category = "run_on_node" expected_result = { action = "result", value = 1 } +expected_result_new_encoding = { action = "return_data", value = "01" } contracts = ["should_pass/test_contracts/nested_struct_args_contract"] -unsupported_profiles = ["debug"] \ No newline at end of file +unsupported_profiles = ["debug"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/Forc.lock index 1b554c4f11a..70665807a59 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/Forc.lock @@ -1,21 +1,22 @@ [[package]] -name = 'core' -source = 'path+from-root-323E392CC41F43FA' +name = "core" +source = "path+from-root-323E392CC41F43FA" [[package]] -name = 'std' -source = 'path+from-root-323E392CC41F43FA' -dependencies = ['core'] +name = "std" +source = "path+from-root-323E392CC41F43FA" +dependencies = ["core"] [[package]] -name = 'storage_access_abi' -source = 'path+from-root-323E392CC41F43FA' -dependencies = ['core'] +name = "storage_access_abi" +source = "path+from-root-323E392CC41F43FA" +dependencies = ["core"] [[package]] -name = 'storage_access_caller' -source = 'member' +name = "storage_access_caller" +source = "member" dependencies = [ - 'std', - 'storage_access_abi', + "core", + "std", + "storage_access_abi", ] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/Forc.toml index e94ec0ec7a6..f92ad47bb65 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/Forc.toml @@ -5,5 +5,6 @@ license = "Apache-2.0" name = "storage_access_caller" [dependencies] +core = { path = "../../../../../../../sway-lib-core" } std = { path = "../../../../../../../sway-lib-std" } storage_access_abi = { path = "../../test_abis/storage_access_abi" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw index e4170911cf1..cf53250bb1e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw @@ -3,12 +3,14 @@ script; use storage_access_abi::*; use std::hash::*; -fn main() -> bool { - let contract_id = 0xcd976bf8d7f3a9b54416c215ee0c732cbae4f9221e281fbc6c6aa8f428f03eb1; - let caller = abi(StorageAccess, contract_id); +#[cfg(experimental_new_encoding = false)] +const CONTRACT_ID = 0xcd976bf8d7f3a9b54416c215ee0c732cbae4f9221e281fbc6c6aa8f428f03eb1; +#[cfg(experimental_new_encoding = true)] +const CONTRACT_ID = 0x3c3c2e05ccf4448075f6008331dc11ccbd434bef6c866e1e4157bb218d2de4ff; +fn main() -> bool { + let caller = abi(StorageAccess, CONTRACT_ID); caller.set_boolean(true); assert(caller.get_boolean() == true); - true } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/test.toml index 2633688329b..9df1e7e9d36 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/test.toml @@ -1,4 +1,5 @@ category = "run_on_node" expected_result = { action = "result", value = 1 } +expected_result_new_encoding = { action = "return_data", value = "01" } contracts = ["should_pass/test_contracts/storage_access_contract"] -unsupported_profiles = ["debug"] \ No newline at end of file +unsupported_profiles = ["debug"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/array_of_structs_abi/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/array_of_structs_abi/Forc.toml index 49c12f81d9c..d829520c5fe 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/array_of_structs_abi/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_abis/array_of_structs_abi/Forc.toml @@ -1,6 +1,9 @@ [project] authors = ["Fuel Labs "] entry = "main.sw" -implicit-std = false license = "Apache-2.0" name = "array_of_structs_abi" + +[dependencies] +core = { path = "../../../../../../../sway-lib-core" } +std = { path = "../../../../../../../sway-lib-std" } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/array_of_structs_contract/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/array_of_structs_contract/Forc.lock index c287f379877..f07e1d8539e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/array_of_structs_contract/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/array_of_structs_contract/Forc.lock @@ -1,8 +1,25 @@ [[package]] name = "array_of_structs_abi" source = "path+from-root-1DC31120923A1AC6" +dependencies = [ + "core", + "std", +] [[package]] name = "array_of_structs_contract" source = "member" -dependencies = ["array_of_structs_abi"] +dependencies = [ + "array_of_structs_abi", + "core", + "std", +] + +[[package]] +name = "core" +source = "path+from-root-1DC31120923A1AC6" + +[[package]] +name = "std" +source = "path+from-root-1DC31120923A1AC6" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/array_of_structs_contract/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/array_of_structs_contract/Forc.toml index 479700b9375..6638e6ae99d 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/array_of_structs_contract/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/array_of_structs_contract/Forc.toml @@ -1,9 +1,10 @@ [project] authors = ["Fuel Labs "] entry = "main.sw" -implicit-std = false license = "Apache-2.0" name = "array_of_structs_contract" [dependencies] +core = { path = "../../../../../../../sway-lib-core" } +std = { path = "../../../../../../../sway-lib-std" } array_of_structs_abi = { path = "../../test_abis/array_of_structs_abi" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.toml index 94671fb72d4..8bce24f6a24 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.toml @@ -1,4 +1,4 @@ category = "compile" validate_abi = true validate_storage_slots = true -expected_warnings = 1 +expected_warnings = 3 diff --git a/test/src/ir_generation/mod.rs b/test/src/ir_generation/mod.rs index b1e83fa5a1b..855282968a9 100644 --- a/test/src/ir_generation/mod.rs +++ b/test/src/ir_generation/mod.rs @@ -171,7 +171,7 @@ pub(super) async fn run( // Compile core library and reuse it when compiling tests. let engines = Engines::default(); let build_target = BuildTarget::default(); - let core_lib = compile_core(build_target, &engines); + let core_lib = compile_core(build_target, &engines, experimental); // Find all the tests. let all_tests = discover_test_files(); @@ -257,6 +257,12 @@ pub(super) async fn run( let programs = compile_res .expect("there were no errors, so there should be a program"); + if verbose { + println!("Declaration Engine"); + println!("-----------------------"); + println!("{}", engines.de().pretty_print(&engines)); + } + let typed_program = programs.typed.as_ref().unwrap(); // Compile to IR. @@ -514,7 +520,11 @@ fn discover_test_files() -> Vec { test_files } -fn compile_core(build_target: BuildTarget, engines: &Engines) -> namespace::Module { +fn compile_core( + build_target: BuildTarget, + engines: &Engines, + experimental: ExperimentalFlags, +) -> namespace::Module { let manifest_dir = env!("CARGO_MANIFEST_DIR"); let libcore_root_dir = format!("{manifest_dir}/../sway-lib-core"); @@ -526,6 +536,7 @@ fn compile_core(build_target: BuildTarget, engines: &Engines) -> namespace::Modu disable_tests: false, locked: false, ipfs_node: None, + experimental_new_encoding: experimental.new_encoding, }; let res = match forc::test::forc_check::check(check_cmd, engines) { diff --git a/test/src/main.rs b/test/src/main.rs index 2a56aeadc6d..8de613d6298 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -54,6 +54,10 @@ struct Cli { /// Experimental flag for new encoding #[arg(long)] experimental_new_encoding: bool, + + /// Update all output files + #[arg(long)] + update_output_files: bool, } #[derive(Debug, Clone)] @@ -73,6 +77,7 @@ pub struct RunConfig { pub verbose: bool, pub release: bool, pub experimental: ExperimentalFlags, + pub update_output_files: bool, } #[tokio::main] @@ -104,6 +109,7 @@ async fn main() -> Result<()> { experimental: sway_core::ExperimentalFlags { new_encoding: cli.experimental_new_encoding, }, + update_output_files: cli.update_output_files, }; // Check that the tests are consistent