From 910e33bd015e2ea4571e042a856a0cd5c910b93a Mon Sep 17 00:00:00 2001 From: Brandon <89608157+brandonsurh@users.noreply.github.com> Date: Fri, 29 Dec 2023 13:42:27 -0500 Subject: [PATCH 1/9] Implements the `Hash` trait for `EvmAddress` (#5422) ## Description Closes #5291 Adds the `Hash` trait for `EvmAddress`. ## Checklist - [x] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [ ] I have requested a review from the relevant team or maintainers. --- sway-lib-std/src/vm/evm/evm_address.sw | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sway-lib-std/src/vm/evm/evm_address.sw b/sway-lib-std/src/vm/evm/evm_address.sw index da01bba6edd..7706ad08147 100644 --- a/sway-lib-std/src/vm/evm/evm_address.sw +++ b/sway-lib-std/src/vm/evm/evm_address.sw @@ -3,6 +3,7 @@ library; use ::intrinsics::size_of_val; use ::convert::From; +use ::hash::*; /// The `EvmAddress` type, a struct wrapper around the inner `b256` value. pub struct EvmAddress { @@ -35,3 +36,10 @@ impl From for EvmAddress { self.value } } + +impl Hash for EvmAddress { + fn hash(self, ref mut state: Hasher) { + let Address { value } = self; + value.hash(state); + } +} \ No newline at end of file From caa182200956dec1ac1bcac9e2b5fd9f922d9558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20D=2E=20Rodas?= Date: Wed, 3 Jan 2024 02:47:48 -0300 Subject: [PATCH 2/9] Make sure that list of plugins is sorted and unique (#5395) ## Description Fixes #5396, #5402 The sorting is performed by the file_name instead of the full text to be printed or full path ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [x] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers. --- forc/src/cli/commands/plugins.rs | 55 ++++++++++++++++++++++++++------ forc/src/cli/mod.rs | 2 +- forc/src/cli/plugin.rs | 18 ++++++++++- 3 files changed, 64 insertions(+), 11 deletions(-) diff --git a/forc/src/cli/commands/plugins.rs b/forc/src/cli/commands/plugins.rs index 0343020856d..0ade150ea77 100644 --- a/forc/src/cli/commands/plugins.rs +++ b/forc/src/cli/commands/plugins.rs @@ -1,8 +1,12 @@ use crate::cli::PluginsCommand; use anyhow::anyhow; use clap::Parser; +use forc_tracing::println_warning; use forc_util::ForcResult; -use std::path::{Path, PathBuf}; +use std::{ + collections::HashMap, + path::{Path, PathBuf}, +}; use tracing::info; /// Find all forc plugins available via `PATH`. @@ -18,15 +22,52 @@ pub struct Command { describe: bool, } +fn get_file_name(path: &Path) -> String { + if let Some(path_str) = path.file_name().and_then(|path_str| path_str.to_str()) { + path_str.to_owned() + } else { + path.display().to_string() + } +} + pub(crate) fn exec(command: PluginsCommand) -> ForcResult<()> { let PluginsCommand { print_full_path, describe, } = command; + let mut plugins = crate::cli::plugin::find_all() + .map(|path| { + get_plugin_info(path.clone(), print_full_path, describe).map(|info| (path, info)) + }) + .collect::, _>>()? + .into_iter() + .fold(HashMap::new(), |mut acc, (path, content)| { + let bin_name = get_file_name(&path); + acc.entry(bin_name.clone()) + .or_insert_with(|| (bin_name, vec![], content.clone())) + .1 + .push(path); + acc + }) + .into_values() + .map(|(bin_name, mut paths, content)| { + paths.sort(); + paths.dedup(); + (bin_name, paths, content) + }) + .collect::>(); + plugins.sort_by(|a, b| a.0.cmp(&b.0)); + info!("Installed Plugins:"); - for path in crate::cli::plugin::find_all() { - info!("{}", print_plugin(path, print_full_path, describe)?); + for plugin in plugins { + info!("{}", plugin.2); + if plugin.1.len() > 1 { + println_warning(&format!("Multiple paths found for {}", plugin.0)); + for path in plugin.1 { + println_warning(&format!(" {}", path.display())); + } + } } Ok(()) } @@ -72,11 +113,7 @@ fn format_print_description( let display = if print_full_path { path.display().to_string() } else { - path.file_name() - .expect("Failed to read file name") - .to_str() - .expect("Failed to print file name") - .to_string() + get_file_name(&path) }; let description = parse_description_for_plugin(&path); @@ -94,7 +131,7 @@ fn format_print_description( /// paths yielded from plugin::find_all(), as well as that the file names are in valid /// unicode format since file names should be prefixed with `forc-`. Should one of these 2 /// assumptions fail, this function panics. -fn print_plugin(path: PathBuf, print_full_path: bool, describe: bool) -> ForcResult { +fn get_plugin_info(path: PathBuf, print_full_path: bool, describe: bool) -> ForcResult { format_print_description(path, print_full_path, describe) .map_err(|e| anyhow!("Could not get plugin info: {}", e.as_ref()).into()) } diff --git a/forc/src/cli/mod.rs b/forc/src/cli/mod.rs index a304e97faf7..ae8997ee688 100644 --- a/forc/src/cli/mod.rs +++ b/forc/src/cli/mod.rs @@ -106,7 +106,7 @@ pub async fn run_cli() -> ForcResult<()> { Forc::ContractId(command) => contract_id::exec(command), Forc::PredicateRoot(command) => predicate_root::exec(command), Forc::Plugin(args) => { - let output = plugin::execute_external_subcommand(args)?; + let output = plugin::execute_external_subcommand(args, opt.silent)?; let code = output .status .code() diff --git a/forc/src/cli/plugin.rs b/forc/src/cli/plugin.rs index 16a8d072997..47d234df4b9 100644 --- a/forc/src/cli/plugin.rs +++ b/forc/src/cli/plugin.rs @@ -1,6 +1,7 @@ //! Items related to plugin support for `forc`. use anyhow::{bail, Result}; +use forc_tracing::println_warning; use std::{ env, fs, path::{Path, PathBuf}, @@ -14,7 +15,10 @@ use std::{ /// /// E.g. given `foo bar baz` where `foo` is an unrecognized subcommand to `forc`, tries to execute /// `forc-foo bar baz`. -pub(crate) fn execute_external_subcommand(args: Vec) -> Result { +pub(crate) fn execute_external_subcommand( + args: Vec, + silent: bool, +) -> Result { let cmd = args.get(0).expect("`args` must not be empty"); let args = &args[1..]; let path = find_external_subcommand(cmd); @@ -22,6 +26,18 @@ pub(crate) fn execute_external_subcommand(args: Vec) -> Result command, None => bail!("no such subcommand: `{}`", cmd), }; + + if let Ok(forc_path) = std::env::current_exe() { + if !silent && command.parent() != forc_path.parent() { + println_warning(&format!( + "The {} ({}) plugin is in a different directory than forc ({})\n", + cmd, + command.display(), + forc_path.display(), + )); + } + } + let output = process::Command::new(command) .stdin(process::Stdio::inherit()) .stdout(process::Stdio::inherit()) From 3210aef096f042948d0de9d8fbac69446e8dcaa2 Mon Sep 17 00:00:00 2001 From: Brandon <89608157+brandonsurh@users.noreply.github.com> Date: Wed, 3 Jan 2024 07:39:22 -0500 Subject: [PATCH 3/9] Added tests for the `sqrt()` method in `math.sw` (#5423) ## Description Closes #5330 Previously, there were no tests for the `sqrt()` method in `math.sw`. This adds square root tests in the Rust test suite. Other tests are found here: - [`pow()`](https://github.com/FuelLabs/sway/blob/master/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/src/main.sw) - [`log()` and `log2()`](https://github.com/FuelLabs/sway/blob/master/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/src/main.sw) ## Checklist - [x] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [ ] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: Joshua Batty --- sway-lib-std/src/math.sw | 224 +++++++++++++++++- .../stdlib/exponentiation_test/Forc.lock | 13 - .../stdlib/exponentiation_test/Forc.toml | 8 - .../exponentiation_test/json_abi_oracle.json | 25 -- .../stdlib/exponentiation_test/src/main.sw | 116 --------- .../stdlib/exponentiation_test/test.toml | 3 - .../stdlib/logarithmic_test/.gitignore | 2 - .../stdlib/logarithmic_test/Forc.lock | 13 - .../stdlib/logarithmic_test/Forc.toml | 8 - .../logarithmic_test/json_abi_oracle.json | 25 -- .../stdlib/logarithmic_test/src/main.sw | 53 ----- .../stdlib/logarithmic_test/test.toml | 4 - 12 files changed, 222 insertions(+), 272 deletions(-) delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/Forc.lock delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/Forc.toml delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/json_abi_oracle.json delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/src/main.sw delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/test.toml delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/.gitignore delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/Forc.lock delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/Forc.toml delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/json_abi_oracle.json delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/src/main.sw delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/test.toml diff --git a/sway-lib-std/src/math.sw b/sway-lib-std/src/math.sw index 31bcad2645d..45ceb4f5d66 100644 --- a/sway-lib-std/src/math.sw +++ b/sway-lib-std/src/math.sw @@ -195,14 +195,234 @@ impl BinaryLogarithm for u8 { } #[test] -fn u256_pow_tests() { - let five = 0x0000000000000000000000000000000000000000000000000000000000000005u256; +fn square_root_test_math_sw() { + use ::assert::*; + + let max_u64 = u64::max(); + let max_u32 = u32::max(); + let max_u16 = u16::max(); + let max_u8 = u8::max(); + + // u64 + assert(1.sqrt() == 1); + assert(4.sqrt() == 2); + assert(9.sqrt() == 3); + assert(144.sqrt() == 12); + assert(1024.sqrt() == 32); + assert(10000000000000000.sqrt() == 100000000); + assert(0.sqrt() == 0); + assert(2.sqrt() == 1); + assert(5.sqrt() == 2); + assert(1000.sqrt() == 31); + assert(max_u64.sqrt() == 4294967295); + + // u32 + assert(1u32.sqrt() == 1); + assert(4u32.sqrt() == 2); + assert(9u32.sqrt() == 3); + assert(144u32.sqrt() == 12); + assert(1024u32.sqrt() == 32); + assert(100000000u32.sqrt() == 10000); + assert(0u32.sqrt() == 0); + assert(2u32.sqrt() == 1); + assert(5u32.sqrt() == 2); + assert(1000u32.sqrt() == 31); + assert(max_u32.sqrt() == 65535); + + // u16 + assert(1u16.sqrt() == 1); + assert(4u16.sqrt() == 2); + assert(9u16.sqrt() == 3); + assert(144u16.sqrt() == 12); + assert(1024u16.sqrt() == 32); + assert(50625u16.sqrt() == 225); + assert(0u16.sqrt() == 0); + assert(2u16.sqrt() == 1); + assert(5u16.sqrt() == 2); + assert(1000u16.sqrt() == 31); + assert(max_u16.sqrt() == 255); + + // u8 + assert(1u8.sqrt() == 1); + assert(4u8.sqrt() == 2); + assert(9u8.sqrt() == 3); + assert(144u8.sqrt() == 12); + assert(0u8.sqrt() == 0); + assert(2u8.sqrt() == 1); + assert(5u8.sqrt() == 2); + assert(max_u8.sqrt() == 15); +} +#[test] +fn exponentiation_test_math_sw() { use ::assert::*; + + // u256 + let five = 0x0000000000000000000000000000000000000000000000000000000000000005u256; // 5^2 = 25 = 0x19 assert_eq(five.pow(2), 0x0000000000000000000000000000000000000000000000000000000000000019u256); // 5^28 = 0x204FCE5E3E2502611 (see https://www.wolframalpha.com/input?i=convert+5%5E28+in+hex) assert_eq(five.pow(28), 0x0000000000000000204FCE5E3E2502611u256); + + // u64 + assert(2.pow(2) == 4); + assert(2 ** 2 == 4); + + assert(2.pow(3) == 8); + assert(2 ** 3 == 8); + + assert(42.pow(2) == 1764); + assert(42 ** 2 == 1764); + + assert(42.pow(3) == 74088); + assert(42 ** 3 == 74088); + + assert(100.pow(5) == 10000000000); + assert(100 ** 5 == 10000000000); + + assert(100.pow(8) == 10000000000000000); + assert(100 ** 8 == 10000000000000000); + + assert(100.pow(9) == 1000000000000000000); + assert(100 ** 9 == 1000000000000000000); + + assert(2.pow(0) == 1); + assert(2 ** 0 == 1); + + assert(0.pow(1) == 0); + assert(0 ** 1 == 0); + + assert(0.pow(2) == 0); + assert(0 ** 2 == 0); + + // u32 + assert(2u32.pow(2u32) == 4u32); + assert(2u32 ** 2u32 == 4u32); + + assert(2u32.pow(3u32) == 8u32); + assert(2u32 ** 3u32 == 8u32); + + assert(42u32.pow(2u32) == 1764u32); + assert(42u32 ** 2u32 == 1764u32); + + assert(100u32.pow(4u32) == 100000000u32); + assert(100u32 ** 4u32 == 100000000u32); + + assert(2u32.pow(0u32) == 1u32); + assert(2u32 ** 0u32 == 1u32); + + assert(0u32.pow(1u32) == 0u32); + assert(0u32 ** 1u32 == 0u32); + + assert(0u32.pow(2u32) == 0u32); + assert(0u32 ** 2u32 == 0u32); + + // u16 + assert(2u16.pow(2u32) == 4u16); + assert(2u16 ** 2u32 == 4u16); + + assert(2u16.pow(3u32) == 8u16); + assert(2u16 ** 3u32 == 8u16); + + assert(42u16.pow(2u32) == 1764u16); + assert(42u16 ** 2u32 == 1764u16); + + assert(20u16.pow(3u32) == 8000u16); + assert(20u16 ** 3u32 == 8000u16); + + assert(15u16.pow(4u32) == 50625u16); + assert(15u16 ** 4u32 == 50625u16); + + assert(2u16.pow(0u32) == 1u16); + assert(2u16 ** 0u32 == 1u16); + + assert(0u16.pow(1u32) == 0u16); + assert(0u16 ** 1u32 == 0u16); + + assert(0u16.pow(2u32) == 0u16); + assert(0u16 ** 2u32 == 0u16); + + // u8 + assert(2u8.pow(2u32) == 4u8); + assert(2u8 ** 2u32 == 4u8); + + assert(2u8.pow(3u32) == 8u8); + assert(2u8 ** 3u32 == 8u8); + + assert(4u8.pow(3u32) == 64u8); + assert(4u8 ** 3u32 == 64u8); + + assert(3u8.pow(4u32) == 81u8); + assert(3u8 ** 4u32 == 81u8); + + assert(10u8.pow(2u32) == 100u8); + assert(10u8 ** 2u32 == 100u8); + + assert(5u8.pow(3u32) == 125u8); + assert(5u8 ** 3u32 == 125u8); + + assert(3u8.pow(5u32) == 243u8); + assert(3u8 ** 5u32 == 243u8); + + assert(2u8.pow(0u32) == 1u8); + assert(2u8 ** 0u32 == 1u8); + + assert(0u8.pow(1u32) == 0u8); + assert(0u8 ** 1u32 == 0u8); + + assert(0u8.pow(2u32) == 0u8); + assert(0u8 ** 2u32 == 0u8); +} + +#[test] +fn logarithmic_test_math_sw() { + use ::assert::*; + + let max_u64 = u64::max(); + let max_u32 = u32::max(); + let max_u16 = u16::max(); + let max_u8 = u8::max(); + + // u64 + assert(2.log(2) == 1); + assert(2.log2() == 1); + assert(1.log(3) == 0); + assert(8.log(2) == 3); + assert(8.log2() == 3); + assert(100.log(10) == 2); + assert(100.log(2) == 6); + assert(100.log2() == 6); + assert(100.log(9) == 2); + assert(max_u64.log(10) == 19); + assert(max_u64.log(2) == 63); + assert(max_u64.log2() == 63); + + // u32 + assert(2u32.log(2u32) == 1u32); + assert(100u32.log(10u32) == 2u32); + assert(125u32.log(5u32) == 3u32); + assert(256u32.log(4u32) == 4u32); + assert(max_u32.log(10) == 9); + assert(max_u32.log(2) == 31); + assert(max_u32.log2() == 31); + + // u16 + assert(7u16.log(7u16) == 1u16); + assert(49u16.log(7u16) == 2u16); + assert(27u16.log(3u16) == 3u16); + assert(1024u16.log(2u16) == 10u16); + assert(max_u16.log(10) == 4); + assert(max_u16.log(2) == 15); + assert(max_u16.log2() == 15); + + // u8 + assert(20u8.log(20u8) == 1u8); + assert(81u8.log(9u8) == 2u8); + assert(36u8.log(6u8) == 2u8); + assert(125u8.log(5u8) == 3u8); + assert(max_u8.log(10) == 2); + assert(max_u8.log(2) == 7); + assert(max_u8.log2() == 7); } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/Forc.lock deleted file mode 100644 index c62af715ca4..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/Forc.lock +++ /dev/null @@ -1,13 +0,0 @@ -[[package]] -name = 'core' -source = 'path+from-root-31441D12B1FE5745' - -[[package]] -name = 'exponentiation_test' -source = 'member' -dependencies = ['std'] - -[[package]] -name = 'std' -source = 'path+from-root-31441D12B1FE5745' -dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/Forc.toml deleted file mode 100644 index 7e0f76dc98f..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/Forc.toml +++ /dev/null @@ -1,8 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -license = "Apache-2.0" -name = "exponentiation_test" - -[dependencies] -std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/json_abi_oracle.json deleted file mode 100644 index 03b2f150939..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/json_abi_oracle.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "configurables": [], - "functions": [ - { - "attributes": null, - "inputs": [], - "name": "main", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } - } - ], - "loggedTypes": [], - "messagesTypes": [], - "types": [ - { - "components": null, - "type": "bool", - "typeId": 0, - "typeParameters": null - } - ] -} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/src/main.sw deleted file mode 100644 index d3a37bba662..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/src/main.sw +++ /dev/null @@ -1,116 +0,0 @@ -script; - -use std::math::*; - -fn main() -> bool { - // u64 - assert(2.pow(2) == 4); - assert(2 ** 2 == 4); - - assert(2.pow(3) == 8); - assert(2 ** 3 == 8); - - assert(42.pow(2) == 1764); - assert(42 ** 2 == 1764); - - assert(42.pow(3) == 74088); - assert(42 ** 3 == 74088); - - assert(100.pow(5) == 10000000000); - assert(100 ** 5 == 10000000000); - - assert(100.pow(8) == 10000000000000000); - assert(100 ** 8 == 10000000000000000); - - assert(100.pow(9) == 1000000000000000000); - assert(100 ** 9 == 1000000000000000000); - - assert(2.pow(0) == 1); - assert(2 ** 0 == 1); - - assert(0.pow(1) == 0); - assert(0 ** 1 == 0); - - assert(0.pow(2) == 0); - assert(0 ** 2 == 0); - - // u32 - assert(2u32.pow(2u32) == 4u32); - assert(2u32 ** 2u32 == 4u32); - - assert(2u32.pow(3u32) == 8u32); - assert(2u32 ** 3u32 == 8u32); - - assert(42u32.pow(2u32) == 1764u32); - assert(42u32 ** 2u32 == 1764u32); - - assert(100u32.pow(4u32) == 100000000u32); - assert(100u32 ** 4u32 == 100000000u32); - - assert(2u32.pow(0u32) == 1u32); - assert(2u32 ** 0u32 == 1u32); - - assert(0u32.pow(1u32) == 0u32); - assert(0u32 ** 1u32 == 0u32); - - assert(0u32.pow(2u32) == 0u32); - assert(0u32 ** 2u32 == 0u32); - - // u16 - assert(2u16.pow(2u32) == 4u16); - assert(2u16 ** 2u32 == 4u16); - - assert(2u16.pow(3u32) == 8u16); - assert(2u16 ** 3u32 == 8u16); - - assert(42u16.pow(2u32) == 1764u16); - assert(42u16 ** 2u32 == 1764u16); - - assert(20u16.pow(3u32) == 8000u16); - assert(20u16 ** 3u32 == 8000u16); - - assert(15u16.pow(4u32) == 50625u16); - assert(15u16 ** 4u32 == 50625u16); - - assert(2u16.pow(0u32) == 1u16); - assert(2u16 ** 0u32 == 1u16); - - assert(0u16.pow(1u32) == 0u16); - assert(0u16 ** 1u32 == 0u16); - - assert(0u16.pow(2u32) == 0u16); - assert(0u16 ** 2u32 == 0u16); - - // u8 - assert(2u8.pow(2u32) == 4u8); - assert(2u8 ** 2u32 == 4u8); - - assert(2u8.pow(3u32) == 8u8); - assert(2u8 ** 3u32 == 8u8); - - assert(4u8.pow(3u32) == 64u8); - assert(4u8 ** 3u32 == 64u8); - - assert(3u8.pow(4u32) == 81u8); - assert(3u8 ** 4u32 == 81u8); - - assert(10u8.pow(2u32) == 100u8); - assert(10u8 ** 2u32 == 100u8); - - assert(5u8.pow(3u32) == 125u8); - assert(5u8 ** 3u32 == 125u8); - - assert(3u8.pow(5u32) == 243u8); - assert(3u8 ** 5u32 == 243u8); - - assert(2u8.pow(0u32) == 1u8); - assert(2u8 ** 0u32 == 1u8); - - assert(0u8.pow(1u32) == 0u8); - assert(0u8 ** 1u32 == 0u8); - - assert(0u8.pow(2u32) == 0u8); - assert(0u8 ** 2u32 == 0u8); - - true -} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/test.toml deleted file mode 100644 index ace9e6f3186..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/test.toml +++ /dev/null @@ -1,3 +0,0 @@ -category = "run" -expected_result = { action = "return", value = 1 } -validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/.gitignore b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/.gitignore deleted file mode 100644 index 77d3844f58c..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -out -target diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/Forc.lock deleted file mode 100644 index 281300f7110..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/Forc.lock +++ /dev/null @@ -1,13 +0,0 @@ -[[package]] -name = 'core' -source = 'path+from-root-69347707506DB9FA' - -[[package]] -name = 'logarithmic_test' -source = 'member' -dependencies = ['std'] - -[[package]] -name = 'std' -source = 'path+from-root-69347707506DB9FA' -dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/Forc.toml deleted file mode 100644 index 19fdea555c6..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/Forc.toml +++ /dev/null @@ -1,8 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -license = "Apache-2.0" -name = "logarithmic_test" - -[dependencies] -std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/json_abi_oracle.json deleted file mode 100644 index 03b2f150939..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/json_abi_oracle.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "configurables": [], - "functions": [ - { - "attributes": null, - "inputs": [], - "name": "main", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } - } - ], - "loggedTypes": [], - "messagesTypes": [], - "types": [ - { - "components": null, - "type": "bool", - "typeId": 0, - "typeParameters": null - } - ] -} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/src/main.sw deleted file mode 100644 index d6f3122b65c..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/src/main.sw +++ /dev/null @@ -1,53 +0,0 @@ -script; - -use std::math::*; - -fn main() -> bool { - let max_u64 = u64::max(); - let max_u32 = u32::max(); - let max_u16 = u16::max(); - let max_u8 = u8::max(); - - // u64 - assert(2.log(2) == 1); - assert(2.log2() == 1); - assert(1.log(3) == 0); - assert(8.log(2) == 3); - assert(8.log2() == 3); - assert(100.log(10) == 2); - assert(100.log(2) == 6); - assert(100.log2() == 6); - assert(100.log(9) == 2); - assert(max_u64.log(10) == 19); - assert(max_u64.log(2) == 63); - assert(max_u64.log2() == 63); - - // u32 - assert(2u32.log(2u32) == 1u32); - assert(100u32.log(10u32) == 2u32); - assert(125u32.log(5u32) == 3u32); - assert(256u32.log(4u32) == 4u32); - assert(max_u32.log(10) == 9); - assert(max_u32.log(2) == 31); - assert(max_u32.log2() == 31); - - // u16 - assert(7u16.log(7u16) == 1u16); - assert(49u16.log(7u16) == 2u16); - assert(27u16.log(3u16) == 3u16); - assert(1024u16.log(2u16) == 10u16); - assert(max_u16.log(10) == 4); - assert(max_u16.log(2) == 15); - assert(max_u16.log2() == 15); - - // u8 - assert(20u8.log(20u8) == 1u8); - assert(81u8.log(9u8) == 2u8); - assert(36u8.log(6u8) == 2u8); - assert(125u8.log(5u8) == 3u8); - assert(max_u8.log(10) == 2); - assert(max_u8.log(2) == 7); - assert(max_u8.log2() == 7); - - true -} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/test.toml deleted file mode 100644 index 8a4cdfa83e7..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/test.toml +++ /dev/null @@ -1,4 +0,0 @@ -category = "run" -expected_result = { action = "return", value = 1 } -validate_abi = true -expected_warnings = 15 From 848e762218e5a42b283b4277543ef4ff0072f027 Mon Sep 17 00:00:00 2001 From: Brandon <89608157+brandonsurh@users.noreply.github.com> Date: Wed, 3 Jan 2024 08:22:17 -0500 Subject: [PATCH 4/9] Added `assert_ne(x, y)` function (#5426) ## Description Closes #5321 Added an assertion that mirrors the existing `assert_eq(x, y)` function. The `assert_ne(x, y)` function asserts that the two passed values are not equal. This removes the need for the workaround `assert(x != y)`. Documentation was updated in all areas that `assert_eq()` is referenced. Tests were created similarly to the `assert_eq()` tests. The function was also added to [`prelude.sw`](https://github.com/brandonsurh/sway/blob/9ee4b7a85d54cf19aea29ad63fdfb992d17d95ce/sway-lib-std/src/prelude.sw#L20). ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [x] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [ ] I have requested a review from the relevant team or maintainers. --- .../book/src/introduction/standard_library.md | 1 + docs/reference/src/SUMMARY.md | 1 + .../src/code/operations/assertions/src/lib.sw | 10 +- .../src/documentation/misc/prelude.md | 1 + .../operations/assertions/assert-ne.md | 11 + .../operations/assertions/index.md | 1 + sway-lib-std/src/assert.sw | 30 +- sway-lib-std/src/error_signals.sw | 7 + sway-lib-std/src/prelude.sw | 2 +- .../should_pass/stdlib/assert_ne/.gitignore | 4 + .../should_pass/stdlib/assert_ne/Forc.lock | 13 + .../should_pass/stdlib/assert_ne/Forc.toml | 8 + .../stdlib/assert_ne/json_abi_oracle.json | 337 ++++++++++++++++++ .../should_pass/stdlib/assert_ne/src/main.sw | 74 ++++ .../should_pass/stdlib/assert_ne/test.toml | 3 + .../stdlib/assert_ne_revert/.gitignore | 8 + .../stdlib/assert_ne_revert/Forc.lock | 13 + .../stdlib/assert_ne_revert/Forc.toml | 8 + .../assert_ne_revert/json_abi_oracle.json | 48 +++ .../stdlib/assert_ne_revert/src/main.sw | 5 + .../stdlib/assert_ne_revert/test.toml | 3 + 21 files changed, 585 insertions(+), 3 deletions(-) create mode 100644 docs/reference/src/documentation/operations/assertions/assert-ne.md create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/.gitignore create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/.gitignore create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/test.toml diff --git a/docs/book/src/introduction/standard_library.md b/docs/book/src/introduction/standard_library.md index 1c5c101f93b..01c98a0cc37 100644 --- a/docs/book/src/introduction/standard_library.md +++ b/docs/book/src/introduction/standard_library.md @@ -41,6 +41,7 @@ The current version of the prelude lives in [`std::prelude`](https://github.com/ - [`std::result::Result`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/result.sw), an enum for functions that may succeed or fail. - [`std::assert::assert`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/assert.sw), a function that reverts the VM if the condition provided to it is `false`. - [`std::assert::assert_eq`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/assert.sw), a function that reverts the VM and logs its two inputs `v1` and `v2` if the condition `v1` == `v2` is `false`. +- [`std::assert::assert_ne`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/assert.sw), a function that reverts the VM and logs its two inputs `v1` and `v2` if the condition `v1` != `v2` is `false`. - [`std::revert::require`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/revert.sw), a function that reverts the VM and logs a given value if the condition provided to it is `false`. - [`std::revert::revert`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/revert.sw), a function that reverts the VM. - [`std::logging::log`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/logging.sw), a function that logs arbitrary stack types. diff --git a/docs/reference/src/SUMMARY.md b/docs/reference/src/SUMMARY.md index d167f50b073..d370f93cf0d 100644 --- a/docs/reference/src/SUMMARY.md +++ b/docs/reference/src/SUMMARY.md @@ -89,6 +89,7 @@ - [require](./documentation/operations/assertions/require.md) - [revert](./documentation/operations/assertions/revert.md) - [assert_eq](./documentation/operations/assertions/assert-eq.md) + - [assert_ne](./documentation/operations/assertions/assert-ne.md) - [Address Namespace](./documentation/operations/namespace/index.md) - [Address](./documentation/operations/namespace/address.md) - [ContractId](./documentation/operations/namespace/contract-id.md) diff --git a/docs/reference/src/code/operations/assertions/src/lib.sw b/docs/reference/src/code/operations/assertions/src/lib.sw index 03a2814f04f..e14724c0b30 100644 --- a/docs/reference/src/code/operations/assertions/src/lib.sw +++ b/docs/reference/src/code/operations/assertions/src/lib.sw @@ -19,8 +19,16 @@ fn reverts() { #[allow(dead_code)] // ANCHOR: assert_eq -fn compare(a: u64, b: u64) { +fn compare_eq(a: u64, b: u64) { assert_eq(a, b); // code } // ANCHOR_END: assert_eq + +#[allow(dead_code)] +// ANCHOR: assert_ne +fn compare_ne(a: u64, b: u64) { + assert_ne(a, b); + // code +} +// ANCHOR_END: assert_ne \ No newline at end of file diff --git a/docs/reference/src/documentation/misc/prelude.md b/docs/reference/src/documentation/misc/prelude.md index 689aca16605..98292d78bab 100644 --- a/docs/reference/src/documentation/misc/prelude.md +++ b/docs/reference/src/documentation/misc/prelude.md @@ -18,6 +18,7 @@ The prelude contains the following: - [`assert`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/assert.sw): A module containing - `assert`: A function that reverts the VM if the condition provided to it is false - `assert_eq`: A function that reverts the VM and logs its two inputs v1 and v2 if the condition v1 == v2 is false + - `assert_ne`: A function that reverts the VM and logs its two inputs v1 and v2 if the condition v1 != v2 is false - [`revert`](https://github.com/FuelLabs/sway/blob/master/sway-lib-std/src/revert.sw): A module containing - `require`: A function that reverts and logs a given value if the condition is `false` - `revert`: A function that reverts diff --git a/docs/reference/src/documentation/operations/assertions/assert-ne.md b/docs/reference/src/documentation/operations/assertions/assert-ne.md new file mode 100644 index 00000000000..8aa99d9d3f6 --- /dev/null +++ b/docs/reference/src/documentation/operations/assertions/assert-ne.md @@ -0,0 +1,11 @@ +# assert_ne + +The `assert_ne` function is automatically imported into every program from the [prelude](../../misc/prelude.md). It takes two expressions which are compared and the result is a [Boolean](../../language/built-ins/boolean.md). If the value is `false` then the virtual machine will revert. + +## Example + +Here is a function which asserts that `a` and `b` must not be equal. + +```sway +{{#include ../../../code/operations/assertions/src/lib.sw:assert_ne}} +``` diff --git a/docs/reference/src/documentation/operations/assertions/index.md b/docs/reference/src/documentation/operations/assertions/index.md index 175f0e51c3c..aeb78704b1b 100644 --- a/docs/reference/src/documentation/operations/assertions/index.md +++ b/docs/reference/src/documentation/operations/assertions/index.md @@ -13,3 +13,4 @@ Handling exceptions may be done through [if expressions](../../language/control- - [`require`](require.md): Checks if a `condition` is `true` otherwise logs a `value` and reverts - [`revert`](revert.md): Reverts the virtual machine with the provided exit code - [`assert_eq`](assert-eq.md): Checks if `a` and `b` are equal otherwise reverts +- [`assert_ne`](assert-ne.md): Checks if `a` and `b` are not equal otherwise reverts diff --git a/sway-lib-std/src/assert.sw b/sway-lib-std/src/assert.sw index d345e303bc7..5c3d28f304b 100644 --- a/sway-lib-std/src/assert.sw +++ b/sway-lib-std/src/assert.sw @@ -3,7 +3,7 @@ library; use ::logging::log; use ::revert::revert; -use ::error_signals::{FAILED_ASSERT_SIGNAL, FAILED_ASSERT_EQ_SIGNAL}; +use ::error_signals::{FAILED_ASSERT_SIGNAL, FAILED_ASSERT_EQ_SIGNAL, FAILED_ASSERT_NE_SIGNAL}; /// Asserts that the given `condition` will always be `true` during runtime. @@ -63,3 +63,31 @@ pub fn assert_eq(v1: T, v2: T) where T: Eq { revert(FAILED_ASSERT_EQ_SIGNAL); } } + +/// Asserts that the given values `v1` & `v2` will never be equal during runtime. +/// +/// # Arguments +/// +/// * `v1`: [T] - The first value to compare. +/// * `v2`: [T] - The second value to compare. +/// +/// # Reverts +/// +/// * Reverts when `v1` == `v2`. +/// +/// # Examples +/// +/// ```sway +/// fn foo(a: u64, b: u64) { +/// assert_ne(a, b); +/// // if code execution continues, that means `a` is not equal to `b` +/// log("a is not equal to b"); +/// } +/// ``` +pub fn assert_ne(v1: T, v2: T) where T: Eq { + if (v1 == v2) { + log(v1); + log(v2); + revert(FAILED_ASSERT_NE_SIGNAL); + } +} diff --git a/sway-lib-std/src/error_signals.sw b/sway-lib-std/src/error_signals.sw index ae6dedefd7f..cff0cfcbe5c 100644 --- a/sway-lib-std/src/error_signals.sw +++ b/sway-lib-std/src/error_signals.sw @@ -28,3 +28,10 @@ pub const FAILED_ASSERT_EQ_SIGNAL = 0xffff_ffff_ffff_0003; /// /// The value is: 18446744073709486084 pub const FAILED_ASSERT_SIGNAL = 0xffff_ffff_ffff_0004; + +/// A revert with this value signals that it was caused by a failing call to `std::assert::assert_ne`. +/// +/// # Additional Information +/// +/// The value is: 18446744073709486085 +pub const FAILED_ASSERT_NE_SIGNAL = 0xffff_ffff_ffff_0005; \ No newline at end of file diff --git a/sway-lib-std/src/prelude.sw b/sway-lib-std/src/prelude.sw index b96483e7d6e..3cd36ad0fe1 100644 --- a/sway-lib-std/src/prelude.sw +++ b/sway-lib-std/src/prelude.sw @@ -17,7 +17,7 @@ use ::storage::storage_map::*; use ::vec::Vec; // Error handling -use ::assert::{assert, assert_eq}; +use ::assert::{assert, assert_eq, assert_ne}; use ::option::Option::{self, *}; use ::result::Result::{self, *}; use ::revert::{require, revert}; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/.gitignore b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/.gitignore new file mode 100644 index 00000000000..2b1d140a501 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/.gitignore @@ -0,0 +1,4 @@ +out +target +out +target diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/Forc.lock new file mode 100644 index 00000000000..2676322e773 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "assert_ne" +source = "member" +dependencies = ["std"] + +[[package]] +name = "core" +source = "path+from-root-075F52DB87742EF3" + +[[package]] +name = "std" +source = "path+from-root-075F52DB87742EF3" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/Forc.toml new file mode 100644 index 00000000000..ab0d51c34f9 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "assert_ne" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/json_abi_oracle.json new file mode 100644 index 00000000000..83d510920fc --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/json_abi_oracle.json @@ -0,0 +1,337 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 2, + "typeArguments": null + } + } + ], + "loggedTypes": [ + { + "logId": 0, + "loggedType": { + "name": "", + "type": 12, + "typeArguments": null + } + }, + { + "logId": 1, + "loggedType": { + "name": "", + "type": 12, + "typeArguments": null + } + }, + { + "logId": 2, + "loggedType": { + "name": "", + "type": 11, + "typeArguments": null + } + }, + { + "logId": 3, + "loggedType": { + "name": "", + "type": 11, + "typeArguments": null + } + }, + { + "logId": 4, + "loggedType": { + "name": "", + "type": 10, + "typeArguments": null + } + }, + { + "logId": 5, + "loggedType": { + "name": "", + "type": 10, + "typeArguments": null + } + }, + { + "logId": 6, + "loggedType": { + "name": "", + "type": 13, + "typeArguments": null + } + }, + { + "logId": 7, + "loggedType": { + "name": "", + "type": 13, + "typeArguments": null + } + }, + { + "logId": 8, + "loggedType": { + "name": "", + "type": 1, + "typeArguments": null + } + }, + { + "logId": 9, + "loggedType": { + "name": "", + "type": 1, + "typeArguments": null + } + }, + { + "logId": 10, + "loggedType": { + "name": "", + "type": 5, + "typeArguments": [] + } + }, + { + "logId": 11, + "loggedType": { + "name": "", + "type": 5, + "typeArguments": [] + } + }, + { + "logId": 12, + "loggedType": { + "name": "", + "type": 9, + "typeArguments": [] + } + }, + { + "logId": 13, + "loggedType": { + "name": "", + "type": 9, + "typeArguments": [] + } + }, + { + "logId": 14, + "loggedType": { + "name": "", + "type": 7, + "typeArguments": [] + } + }, + { + "logId": 15, + "loggedType": { + "name": "", + "type": 7, + "typeArguments": [] + } + }, + { + "logId": 16, + "loggedType": { + "name": "", + "type": 6, + "typeArguments": [] + } + }, + { + "logId": 17, + "loggedType": { + "name": "", + "type": 6, + "typeArguments": [] + } + }, + { + "logId": 18, + "loggedType": { + "name": "", + "type": 3, + "typeArguments": [] + } + }, + { + "logId": 19, + "loggedType": { + "name": "", + "type": 3, + "typeArguments": [] + } + }, + { + "logId": 20, + "loggedType": { + "name": "", + "type": 3, + "typeArguments": [] + } + }, + { + "logId": 21, + "loggedType": { + "name": "", + "type": 3, + "typeArguments": [] + } + } + ], + "messagesTypes": [], + "types": [ + { + "components": [ + { + "name": "__array_element", + "type": 1, + "typeArguments": null + } + ], + "type": "[_; 2]", + "typeId": 0, + "typeParameters": null + }, + { + "components": null, + "type": "b256", + "typeId": 1, + "typeParameters": null + }, + { + "components": null, + "type": "bool", + "typeId": 2, + "typeParameters": null + }, + { + "components": [ + { + "name": "Address", + "type": 5, + "typeArguments": null + }, + { + "name": "ContractId", + "type": 9, + "typeArguments": null + } + ], + "type": "enum std::identity::Identity", + "typeId": 3, + "typeParameters": null + }, + { + "components": null, + "type": "raw untyped ptr", + "typeId": 4, + "typeParameters": null + }, + { + "components": [ + { + "name": "value", + "type": 1, + "typeArguments": null + } + ], + "type": "struct std::address::Address", + "typeId": 5, + "typeParameters": null + }, + { + "components": [ + { + "name": "bytes", + "type": 0, + "typeArguments": null + } + ], + "type": "struct std::b512::B512", + "typeId": 6, + "typeParameters": null + }, + { + "components": [ + { + "name": "buf", + "type": 8, + "typeArguments": null + }, + { + "name": "len", + "type": 12, + "typeArguments": null + } + ], + "type": "struct std::bytes::Bytes", + "typeId": 7, + "typeParameters": null + }, + { + "components": [ + { + "name": "ptr", + "type": 4, + "typeArguments": null + }, + { + "name": "cap", + "type": 12, + "typeArguments": null + } + ], + "type": "struct std::bytes::RawBytes", + "typeId": 8, + "typeParameters": null + }, + { + "components": [ + { + "name": "value", + "type": 1, + "typeArguments": null + } + ], + "type": "struct std::contract_id::ContractId", + "typeId": 9, + "typeParameters": null + }, + { + "components": null, + "type": "u16", + "typeId": 10, + "typeParameters": null + }, + { + "components": null, + "type": "u32", + "typeId": 11, + "typeParameters": null + }, + { + "components": null, + "type": "u64", + "typeId": 12, + "typeParameters": null + }, + { + "components": null, + "type": "u8", + "typeId": 13, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/src/main.sw new file mode 100644 index 00000000000..16072d766a6 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/src/main.sw @@ -0,0 +1,74 @@ +script; + +use std::bytes::Bytes; +use std::b512::B512; + +fn main() -> bool { + + // test_assert_ne_u64 + let a = 42; + let b = 40; + assert_ne(a, b); + + // test_assert_ne_u32 + let c = 42u32; + let d = 40u32; + assert_ne(c, d); + + // test_assert_ne_u16 + let e = 42u16; + let f = 40u16; + assert_ne(e, f); + + // test_assert_ne_u8 + let g = 42u8; + let h = 40u8; + assert_ne(g, h); + + // test_assert_ne_b256 + let i: b256 = 0b0000000000000000000000000000000000000000000000000000000000000001_0000000000000000000000000000000000000000000000000000000000000001_0000000000000000000000000000000000000000000000000000000000000001_0000000000000000000000000000000000000000000000000000000000000010; + let j: b256 = 0b1000000000000000000000000000000000000000000000000000000000000000_1000000000000000000000000000000000000000000000000000000000000000_1000000000000000000000000000000000000000000000000000000000000000_1000000000000000000000000000000000000000000000000000000000000001; + assert_ne(i, j); + + // test_assert_ne_address + let value = 0xBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEF; + let value2 = 0xBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEE; + let k = Address::from(value); + let l = Address::from(value2); + assert_ne(k, l); + + // test_assert_ne_contract_id + let m = ContractId::from(value); + let n = ContractId::from(value2); + assert_ne(m, n); + + // test_assert_ne_bytes + let mut q = Bytes::new(); + let mut r = Bytes::new(); + q.push(42u8); + q.push(11u8); + q.push(69u8); + r.push(42u8); + r.push(11u8); + r.push(70u8); + assert_ne(q, r); + + // test_assert_ne_b512 + let value = 0xBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEF; + let value2 = 0xBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEE; + let s = B512::from((value, value)); + let t = B512::from((value2, value2)); + assert_ne(s, t); + + // test_assert_ne_identity + let value = 0xBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEF; + let value2 = 0xBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEE; + let u = Identity::Address(Address::from(value)); + let v = Identity::Address(Address::from(value2)); + let w = Identity::ContractId(ContractId::from(value)); + let x = Identity::ContractId(ContractId::from(value2)); + assert_ne(u, v); + assert_ne(w, x); + + true +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/test.toml new file mode 100644 index 00000000000..ace9e6f3186 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/test.toml @@ -0,0 +1,3 @@ +category = "run" +expected_result = { action = "return", value = 1 } +validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/.gitignore b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/.gitignore new file mode 100644 index 00000000000..071173e4c24 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/.gitignore @@ -0,0 +1,8 @@ +out +target +out +target +out +target +out +target diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/Forc.lock new file mode 100644 index 00000000000..5ab8f989306 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "assert_ne_revert" +source = "member" +dependencies = ["std"] + +[[package]] +name = "core" +source = "path+from-root-57A6C488795FD4D0" + +[[package]] +name = "std" +source = "path+from-root-57A6C488795FD4D0" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/Forc.toml new file mode 100644 index 00000000000..19c5cda08d2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "assert_ne_revert" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/json_abi_oracle.json new file mode 100644 index 00000000000..bf820505563 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/json_abi_oracle.json @@ -0,0 +1,48 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [ + { + "logId": 0, + "loggedType": { + "name": "", + "type": 1, + "typeArguments": null + } + }, + { + "logId": 1, + "loggedType": { + "name": "", + "type": 1, + "typeArguments": null + } + } + ], + "messagesTypes": [], + "types": [ + { + "components": [], + "type": "()", + "typeId": 0, + "typeParameters": null + }, + { + "components": null, + "type": "u64", + "typeId": 1, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/src/main.sw new file mode 100644 index 00000000000..333c56cfa09 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/src/main.sw @@ -0,0 +1,5 @@ +script; + +fn main() { + assert_ne(1, 1); +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/test.toml new file mode 100644 index 00000000000..feb35f3adf9 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/test.toml @@ -0,0 +1,3 @@ +category = "run" +expected_result = { action = "revert", value = -65531} # 0xffffffffffff0005 as i64 +validate_abi = true From 61c260c10ceba95b0c53c03c2c0898e4ec27490d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20D=2E=20Rodas?= Date: Wed, 3 Jan 2024 11:41:32 -0300 Subject: [PATCH 5/9] Run `forc fmt` on std-lib (#5404) ## Description Run `forc fmt` on the std-lib ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [x] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers. --- .github/workflows/ci.yml | 24 ++ examples/msg_sender/src/main.sw | 4 +- examples/storage_map/src/main.sw | 16 +- examples/storage_variables/src/main.sw | 8 +- examples/storage_vec/src/main.sw | 4 +- examples/subcurrency/src/main.sw | 4 +- examples/vec/src/main.sw | 4 +- .../wallet_contract_caller_script/src/main.sw | 4 +- examples/wallet_smart_contract/src/main.sw | 4 +- sway-lib-std/src/address.sw | 10 +- sway-lib-std/src/alloc.sw | 14 +- sway-lib-std/src/array_conversions/b256.sw | 89 ++++--- sway-lib-std/src/array_conversions/u16.sw | 34 +-- sway-lib-std/src/array_conversions/u256.sw | 89 ++++--- sway-lib-std/src/array_conversions/u32.sw | 140 +++++++---- sway-lib-std/src/array_conversions/u64.sw | 230 ++++++++++-------- sway-lib-std/src/assert.sw | 13 +- sway-lib-std/src/auth.sw | 12 +- sway-lib-std/src/block.sw | 9 +- sway-lib-std/src/bytes.sw | 59 +++-- sway-lib-std/src/bytes_conversions/b256.sw | 20 +- sway-lib-std/src/bytes_conversions/u16.sw | 27 +- sway-lib-std/src/bytes_conversions/u256.sw | 24 +- sway-lib-std/src/bytes_conversions/u32.sw | 84 ++++--- sway-lib-std/src/bytes_conversions/u64.sw | 164 ++++++++----- sway-lib-std/src/call_frames.sw | 26 +- sway-lib-std/src/constants.sw | 6 +- sway-lib-std/src/context.sw | 10 +- sway-lib-std/src/contract_id.sw | 84 +++++-- sway-lib-std/src/ecr.sw | 32 ++- sway-lib-std/src/error_signals.sw | 2 +- sway-lib-std/src/external.sw | 2 +- sway-lib-std/src/flags.sw | 34 +-- sway-lib-std/src/hash.sw | 177 ++++++++++---- sway-lib-std/src/identity.sw | 14 +- sway-lib-std/src/intrinsics.sw | 2 +- sway-lib-std/src/logging.sw | 2 +- sway-lib-std/src/low_level_call.sw | 26 +- sway-lib-std/src/math.sw | 19 +- sway-lib-std/src/message.sw | 11 +- sway-lib-std/src/option.sw | 11 +- sway-lib-std/src/primitive_conversions/str.sw | 6 +- sway-lib-std/src/primitive_conversions/u16.sw | 30 ++- sway-lib-std/src/primitive_conversions/u32.sw | 23 +- sway-lib-std/src/primitive_conversions/u64.sw | 8 +- sway-lib-std/src/primitive_conversions/u8.sw | 36 ++- sway-lib-std/src/registers.sw | 66 +++-- sway-lib-std/src/result.sw | 28 +-- sway-lib-std/src/storage/storable_slice.sw | 14 +- sway-lib-std/src/storage/storage_api.sw | 16 +- sway-lib-std/src/storage/storage_key.sw | 10 +- sway-lib-std/src/storage/storage_map.sw | 31 ++- sway-lib-std/src/storage/storage_string.sw | 8 +- sway-lib-std/src/storage/storage_vec.sw | 39 ++- sway-lib-std/src/string.sw | 27 +- sway-lib-std/src/token.sw | 8 +- sway-lib-std/src/tx.sw | 4 +- sway-lib-std/src/u128.sw | 44 ++-- sway-lib-std/src/u256.sw | 50 ++-- sway-lib-std/src/vec.sw | 26 +- sway-lib-std/src/vm/evm/evm_address.sw | 2 +- swayfmt/src/constants.rs | 2 +- swayfmt/src/items/item_abi/mod.rs | 7 +- swayfmt/src/items/item_impl/mod.rs | 5 +- swayfmt/src/items/item_trait/mod.rs | 15 +- swayfmt/src/items/item_use/mod.rs | 12 +- swayfmt/src/utils/language/expr/mod.rs | 1 + swayfmt/src/utils/language/expr/tests.rs | 12 +- swayfmt/tests/mod.rs | 167 ++++++++++++- .../test.toml | 2 +- 70 files changed, 1430 insertions(+), 817 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80cec72439d..5c6deb102a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,6 +71,30 @@ jobs: - name: Build Sway examples workspace run: cargo run --locked -p forc -- build --locked --path ./docs/reference/src/code/Forc.toml + forc-fmt-check-sway-lib-core: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} + - uses: Swatinem/rust-cache@v2 + - name: Check Sway sway-lib-core formatting + run: cargo run --locked -p forc-fmt -- --check --path ./sway-lib-core + + forc-fmt-check-sway-lib-std: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_VERSION }} + - uses: Swatinem/rust-cache@v2 + - name: Check Sway sway-lib-std formatting + run: cargo run --locked -p forc-fmt -- --check --path ./sway-lib-std + forc-fmt-check-sway-examples: runs-on: ubuntu-latest steps: diff --git a/examples/msg_sender/src/main.sw b/examples/msg_sender/src/main.sw index a01adc8dcf9..e850b19ee5e 100644 --- a/examples/msg_sender/src/main.sw +++ b/examples/msg_sender/src/main.sw @@ -4,9 +4,7 @@ abi MyOwnedContract { fn receive(field_1: u64) -> bool; } -const OWNER = Address::from( - 0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c, -); +const OWNER = Address::from(0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c); impl MyOwnedContract for Contract { fn receive(field_1: u64) -> bool { diff --git a/examples/storage_map/src/main.sw b/examples/storage_map/src/main.sw index 367c4689839..b212164d131 100644 --- a/examples/storage_map/src/main.sw +++ b/examples/storage_map/src/main.sw @@ -29,12 +29,8 @@ impl StorageMapExample for Contract { // ANCHOR: storage_map_insert #[storage(write)] fn insert_into_storage_map() { - let addr1 = Address::from( - 0x0101010101010101010101010101010101010101010101010101010101010101, - ); - let addr2 = Address::from( - 0x0202020202020202020202020202020202020202020202020202020202020202, - ); + let addr1 = Address::from(0x0101010101010101010101010101010101010101010101010101010101010101); + let addr2 = Address::from(0x0202020202020202020202020202020202020202020202020202020202020202); storage.map.insert(addr1, 42); storage.map.insert(addr2, 77); @@ -43,12 +39,8 @@ impl StorageMapExample for Contract { // ANCHOR: storage_map_get #[storage(read, write)] fn get_from_storage_map() { - let addr1 = Address::from( - 0x0101010101010101010101010101010101010101010101010101010101010101, - ); - let addr2 = Address::from( - 0x0202020202020202020202020202020202020202020202020202020202020202, - ); + let addr1 = Address::from(0x0101010101010101010101010101010101010101010101010101010101010101); + let addr2 = Address::from(0x0202020202020202020202020202020202020202020202020202020202020202); storage.map.insert(addr1, 42); storage.map.insert(addr2, 77); diff --git a/examples/storage_variables/src/main.sw b/examples/storage_variables/src/main.sw index 43b2d5e25ab..41042ebc165 100644 --- a/examples/storage_variables/src/main.sw +++ b/examples/storage_variables/src/main.sw @@ -37,9 +37,7 @@ impl StorageExample for Contract { storage .var2 .w - .write( - 0x1111111111111111111111111111111111111111111111111111111111111111, - ); + .write(0x1111111111111111111111111111111111111111111111111111111111111111); storage.var2.z.write(true); } // ANCHOR_END: storage_write @@ -49,9 +47,7 @@ impl StorageExample for Contract { ( storage.var1.x.try_read().unwrap_or(0), storage.var1.y.try_read().unwrap_or(0), - storage.var2.w.try_read().unwrap_or( - 0x0000000000000000000000000000000000000000000000000000000000000000, - ), + storage.var2.w.try_read().unwrap_or(0x0000000000000000000000000000000000000000000000000000000000000000), storage.var2.z.try_read().unwrap_or(false), ) } diff --git a/examples/storage_vec/src/main.sw b/examples/storage_vec/src/main.sw index df572d18a80..c5b60937039 100644 --- a/examples/storage_vec/src/main.sw +++ b/examples/storage_vec/src/main.sw @@ -75,9 +75,7 @@ impl StorageVecContract for Contract { storage.row.push(TableCell::Int(3)); storage .row - .push(TableCell::B256( - 0x0101010101010101010101010101010101010101010101010101010101010101, - )); + .push(TableCell::B256(0x0101010101010101010101010101010101010101010101010101010101010101)); storage.row.push(TableCell::Boolean(true)); } // ANCHOR_END: storage_vec_multiple_types_fn diff --git a/examples/subcurrency/src/main.sw b/examples/subcurrency/src/main.sw index e21e7fdc31a..47290cc2433 100644 --- a/examples/subcurrency/src/main.sw +++ b/examples/subcurrency/src/main.sw @@ -37,9 +37,7 @@ abi Token { // Constants //////////////////////////////////////// /// Address of contract creator. -const MINTER = Address::from( - 0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b, -); +const MINTER = Address::from(0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b); //////////////////////////////////////// // Contract storage diff --git a/examples/vec/src/main.sw b/examples/vec/src/main.sw index e6c02e7d0c3..bc72ee65f6c 100644 --- a/examples/vec/src/main.sw +++ b/examples/vec/src/main.sw @@ -39,9 +39,7 @@ fn main() { let mut row = Vec::new(); row.push(TableCell::Int(3)); - row.push(TableCell::B256( - 0x0101010101010101010101010101010101010101010101010101010101010101, - )); + row.push(TableCell::B256(0x0101010101010101010101010101010101010101010101010101010101010101)); row.push(TableCell::Boolean(true)); // ANCHOR_END: vec_multiple_data_types } diff --git a/examples/wallet_contract_caller_script/src/main.sw b/examples/wallet_contract_caller_script/src/main.sw index d7482c8de15..26507c5a749 100644 --- a/examples/wallet_contract_caller_script/src/main.sw +++ b/examples/wallet_contract_caller_script/src/main.sw @@ -7,9 +7,7 @@ fn main() { let contract_address = 0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b; let caller = abi(Wallet, contract_address); let amount_to_send = 200; - let recipient_address = Address::from( - 0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b, - ); + let recipient_address = Address::from(0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b); caller .send_funds { gas: 10000, diff --git a/examples/wallet_smart_contract/src/main.sw b/examples/wallet_smart_contract/src/main.sw index 9fd9299bd4e..7b2ca272a81 100644 --- a/examples/wallet_smart_contract/src/main.sw +++ b/examples/wallet_smart_contract/src/main.sw @@ -11,9 +11,7 @@ use std::{ // ANCHOR: abi_import use wallet_abi::Wallet; // ANCHOR_END: abi_import -const OWNER_ADDRESS = Address::from( - 0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861, -); +const OWNER_ADDRESS = Address::from(0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861); storage { balance: u64 = 0, diff --git a/sway-lib-std/src/address.sw b/sway-lib-std/src/address.sw index 6f5cc388b92..29e6e0f5137 100644 --- a/sway-lib-std/src/address.sw +++ b/sway-lib-std/src/address.sw @@ -26,17 +26,17 @@ impl core::ops::Eq for Address { /// Functions for casting between the `b256` and `Address` types. impl From for Address { /// Casts raw `b256` data to an `Address`. - /// + /// /// # Arguments /// /// * `bits`: [b256] - The raw `b256` data to be casted. - /// + /// /// # Returns /// /// * [Address] - The newly created `Address` from the raw `b256`. /// /// # Examples - /// + /// /// ```sway /// use std::constants::ZERO_B256; /// @@ -49,13 +49,13 @@ impl From for Address { } /// Casts an `Address` to raw `b256` data. - /// + /// /// # Returns /// /// * [b256] - The underlying raw `b256` data of the `Address`. /// /// # Examples - /// + /// /// ```sway /// use std::constants::ZERO_B256; /// diff --git a/sway-lib-std/src/alloc.sw b/sway-lib-std/src/alloc.sw index 5d3790badb9..1e0958c0b4d 100644 --- a/sway-lib-std/src/alloc.sw +++ b/sway-lib-std/src/alloc.sw @@ -30,7 +30,7 @@ library; /// and the VM Instruction Set for [Memory Allocation](https://fuellabs.github.io/fuel-specs/master/vm/instruction_set.html#aloc-allocate-memory). /// /// # Arguments -/// +/// /// * `count`: [u64] - The number of `size_of` bytes to allocate onto the heap. /// /// # Returns @@ -41,7 +41,7 @@ library; /// /// ```sway /// use std::alloc::alloc; -/// +/// /// fn foo() { /// let ptr = alloc::(2); /// assert(!ptr.is_null()); @@ -56,7 +56,7 @@ pub fn alloc(count: u64) -> raw_ptr { } /// Reallocates the given area of memory. -/// +/// /// # Arguments /// /// * `ptr`: [raw_ptr] - The pointer to the area of memory to reallocate. @@ -64,7 +64,7 @@ pub fn alloc(count: u64) -> raw_ptr { /// * `new_count`: [u64] - The number of new `size_of` bytes to allocate. These are set to 0. /// /// # Returns -/// +/// /// * [raw_ptr] - The pointer to the newly reallocated memory. /// /// # Examples @@ -105,7 +105,7 @@ pub fn realloc(ptr: raw_ptr, count: u64, new_count: u64) -> raw_ptr { /// /// ```sway /// use std::alloc::alloc_bytes; -/// +/// /// fn foo() { /// let ptr = alloc_bytes(2); /// assert(!ptr.is_null()); @@ -120,7 +120,7 @@ pub fn alloc_bytes(count: u64) -> raw_ptr { } /// Reallocates the given area of memory in individual bytes. -/// +/// /// # Arguments /// /// * `ptr`: [raw_ptr] - The pointer to the area of memory to reallocate. @@ -128,7 +128,7 @@ pub fn alloc_bytes(count: u64) -> raw_ptr { /// * `new_count`: [u64] - The number of new bytes to allocate. These are set to 0. /// /// # Returns -/// +/// /// * [raw_ptr] - The pointer to the newly reallocated memory. /// /// # Examples diff --git a/sway-lib-std/src/array_conversions/b256.sw b/sway-lib-std/src/array_conversions/b256.sw index 0019d303150..0aef04b27aa 100644 --- a/sway-lib-std/src/array_conversions/b256.sw +++ b/sway-lib-std/src/array_conversions/b256.sw @@ -5,7 +5,7 @@ use ::assert::assert; impl b256 { /// Converts the `b256` to a sequence of little-endian bytes. - /// + /// /// # Returns /// /// * [[u8; 32]] - An array of 32 `u8` bytes that compose the `b256`. @@ -26,18 +26,21 @@ impl b256 { /// } /// ``` pub fn to_le_bytes(self) -> [u8; 32] { - let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) {r1: (u64, u64, u64, u64)}; + let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) { + r1: (u64, u64, u64, u64) + }; let a = a.to_le_bytes(); let b = b.to_le_bytes(); let c = c.to_le_bytes(); let d = d.to_le_bytes(); - let (a,b,c,d) = (d,c,b,a); + let (a, b, c, d) = (d, c, b, a); - let output = [a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], - b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], - c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], - d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]]; + let output = [ + a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], b[0], b[1], b[2], b[3], + b[4], b[5], b[6], b[7], c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], + ]; output } @@ -45,11 +48,11 @@ impl b256 { /// Converts a sequence of little-endian bytes to a `b256`. /// /// # Arguments - /// + /// /// * `bytes`: [[u8; 32]] - A sequence of 32 `u8` bytes that represent a `b256`. /// /// # Returns - /// + /// /// * [b256] - The resulting `b256` value. /// /// # Examples @@ -67,9 +70,18 @@ impl b256 { /// ``` pub fn from_le_bytes(bytes: [u8; 32]) -> Self { let a = u64::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]]); - let b = u64::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]]); - let c = u64::from_le_bytes([bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23]]); - let d = u64::from_le_bytes([bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31]]); + let b = u64::from_le_bytes([ + bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], + bytes[15], + ]); + let c = u64::from_le_bytes([ + bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], + bytes[23], + ]); + let d = u64::from_le_bytes([ + bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], + bytes[31], + ]); let result = (d, c, b, a); @@ -79,7 +91,7 @@ impl b256 { } /// Converts the `b256` to a sequence of big-endian bytes. - /// + /// /// # Returns /// /// * [[u8; 32]] - An array of 32 `u8` bytes that compose the `b256`. @@ -99,16 +111,19 @@ impl b256 { /// } /// ``` pub fn to_be_bytes(self) -> [u8; 32] { - let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) {r1: (u64, u64, u64, u64)}; + let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) { + r1: (u64, u64, u64, u64) + }; let a = a.to_be_bytes(); let b = b.to_be_bytes(); let c = c.to_be_bytes(); let d = d.to_be_bytes(); - let output = [a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], - b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], - c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], - d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]]; + let output = [ + a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], b[0], b[1], b[2], b[3], + b[4], b[5], b[6], b[7], c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], + ]; output } @@ -116,11 +131,11 @@ impl b256 { /// Converts a sequence of big-endian bytes to a `b256`. /// /// # Arguments - /// + /// /// * `bytes`: [[u8; 32]] - A sequence of 32 `u8` bytes that represent a `b256`. /// /// # Returns - /// + /// /// * [b256] - The resulting `b256` value. /// /// # Examples @@ -138,9 +153,18 @@ impl b256 { /// ``` pub fn from_be_bytes(bytes: [u8; 32]) -> Self { let a = u64::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]]); - let b = u64::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]]); - let c = u64::from_be_bytes([bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23]]); - let d = u64::from_be_bytes([bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31]]); + let b = u64::from_be_bytes([ + bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], + bytes[15], + ]); + let c = u64::from_be_bytes([ + bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], + bytes[23], + ]); + let d = u64::from_be_bytes([ + bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], + bytes[31], + ]); let result = (a, b, c, d); @@ -152,10 +176,11 @@ impl b256 { #[test] fn test_b256_from_le_bytes() { - let bytes = [32_u8, 31_u8, 30_u8, 29_u8, 28_u8, 27_u8, 26_u8, 25_u8, 24_u8, 23_u8, - 22_u8, 21_u8, 20_u8, 19_u8, 18_u8, 17_u8, 16_u8, 15_u8, 14_u8, 13_u8, - 12_u8, 11_u8, 10_u8, 9_u8, 8_u8, 7_u8, 6_u8, 5_u8, 4_u8, 3_u8, - 2_u8, 1_u8]; + let bytes = [ + 32_u8, 31_u8, 30_u8, 29_u8, 28_u8, 27_u8, 26_u8, 25_u8, 24_u8, 23_u8, 22_u8, + 21_u8, 20_u8, 19_u8, 18_u8, 17_u8, 16_u8, 15_u8, 14_u8, 13_u8, 12_u8, 11_u8, + 10_u8, 9_u8, 8_u8, 7_u8, 6_u8, 5_u8, 4_u8, 3_u8, 2_u8, 1_u8, + ]; let x = b256::from_le_bytes(bytes); @@ -173,15 +198,15 @@ fn test_b256_to_le_bytes() { assert(bytes[i.as_u64()] == 32_u8 - i); i += 1_u8; } - } #[test] fn test_b256_from_be_bytes() { - let bytes = [1_u8, 2_u8, 3_u8, 4_u8, 5_u8, 6_u8, 7_u8, 8_u8, 9_u8, 10_u8, - 11_u8, 12_u8, 13_u8, 14_u8, 15_u8, 16_u8, 17_u8, 18_u8, 19_u8, 20_u8, - 21_u8, 22_u8, 23_u8, 24_u8, 25_u8, 26_u8, 27_u8, 28_u8, 29_u8, 30_u8, - 31_u8, 32_u8]; + let bytes = [ + 1_u8, 2_u8, 3_u8, 4_u8, 5_u8, 6_u8, 7_u8, 8_u8, 9_u8, 10_u8, 11_u8, 12_u8, + 13_u8, 14_u8, 15_u8, 16_u8, 17_u8, 18_u8, 19_u8, 20_u8, 21_u8, 22_u8, 23_u8, + 24_u8, 25_u8, 26_u8, 27_u8, 28_u8, 29_u8, 30_u8, 31_u8, 32_u8, + ]; let x = b256::from_be_bytes(bytes); diff --git a/sway-lib-std/src/array_conversions/u16.sw b/sway-lib-std/src/array_conversions/u16.sw index 4a29fb65cf6..06372c55e12 100644 --- a/sway-lib-std/src/array_conversions/u16.sw +++ b/sway-lib-std/src/array_conversions/u16.sw @@ -4,7 +4,7 @@ use ::assert::assert; impl u16 { /// Converts the `u16` to a sequence of little-endian bytes. - /// + /// /// # Returns /// /// * [[u8; 2]] - An array of 2 `u8` bytes that compose the `u16`. @@ -15,7 +15,7 @@ impl u16 { /// fn foo() { /// let x: u16 = 513; /// let result = x.to_le_bytes(); - /// + /// /// assert(result[0] == 1_u8); /// assert(result[1] == 2_u8); /// } @@ -24,12 +24,12 @@ impl u16 { let output = [0_u8, 0_u8]; asm(input: self, off: 0xFF, i: 0x8, output: output, r1) { - and r1 input off; - sb output r1 i0; + and r1 input off; + sb output r1 i0; - srl r1 input i; - and r1 r1 off; - sb output r1 i1; + srl r1 input i; + and r1 r1 off; + sb output r1 i1; output: [u8; 2] } @@ -38,11 +38,11 @@ impl u16 { /// Converts a sequence of little-endian bytes to a `u16`. /// /// # Arguments - /// + /// /// * `bytes`: [[u8; 2]] - A sequence of 2 `u8` bytes that represent a `u16`. /// /// # Returns - /// + /// /// * [u16] - The resulting `u16` value. /// /// # Examples @@ -57,14 +57,14 @@ impl u16 { /// ``` pub fn from_le_bytes(bytes: [u8; 2]) -> Self { asm(a: bytes[0], b: bytes[1], i: 0x8, r1) { - sll r1 b i; - or r1 a r1; + sll r1 b i; + or r1 a r1; r1: u16 } } /// Converts the `u16` to a sequence of big-endian bytes. - /// + /// /// # Returns /// /// * [[u8; 2]] - An array of 2 `u8` bytes that compose the `u16`. @@ -97,11 +97,11 @@ impl u16 { /// Converts a sequence of big-endian bytes to a `u16`. /// /// # Arguments - /// + /// /// * `bytes`: [[u8; 2]] - A sequence of 2 `u8` bytes that represent a `u16`. /// /// # Returns - /// + /// /// * [u16] - The resulting `u16` value. /// /// # Examples @@ -110,14 +110,14 @@ impl u16 { /// fn foo() { /// let bytes = [2_u8, 1_u8]; /// let result = u16::from_be_bytes(bytes); - /// + /// /// assert(result == 513_u16); /// } /// ``` pub fn from_be_bytes(bytes: [u8; 2]) -> Self { asm(a: bytes[0], b: bytes[1], i: 0x8, r1) { - sll r1 a i; - or r1 r1 b; + sll r1 a i; + or r1 r1 b; r1: u16 } } diff --git a/sway-lib-std/src/array_conversions/u256.sw b/sway-lib-std/src/array_conversions/u256.sw index 6947d0e3416..9691f44892d 100644 --- a/sway-lib-std/src/array_conversions/u256.sw +++ b/sway-lib-std/src/array_conversions/u256.sw @@ -5,7 +5,7 @@ use ::assert::assert; impl u256 { /// Converts the `u256` to a sequence of little-endian bytes. - /// + /// /// # Returns /// /// * [[u8; 32]] - An array of 32 `u8` bytes that compose the `u256`. @@ -25,18 +25,21 @@ impl u256 { /// } /// ``` pub fn to_le_bytes(self) -> [u8; 32] { - let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) {r1: (u64, u64, u64, u64)}; + let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) { + r1: (u64, u64, u64, u64) + }; let a = a.to_le_bytes(); let b = b.to_le_bytes(); let c = c.to_le_bytes(); let d = d.to_le_bytes(); - let (a,b,c,d) = (d,c,b,a); + let (a, b, c, d) = (d, c, b, a); - let output = [a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], - b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], - c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], - d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]]; + let output = [ + a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], b[0], b[1], b[2], b[3], + b[4], b[5], b[6], b[7], c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], + ]; output } @@ -44,11 +47,11 @@ impl u256 { /// Converts a sequence of little-endian bytes to a `u256`. /// /// # Arguments - /// + /// /// * `bytes`: [[u8; 32]] - A sequence of 32 `u8` bytes that represent a `u256`. /// /// # Returns - /// + /// /// * [u256] - The resulting `u256` value. /// /// # Examples @@ -66,9 +69,18 @@ impl u256 { /// ``` pub fn from_le_bytes(bytes: [u8; 32]) -> Self { let a = u64::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]]); - let b = u64::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]]); - let c = u64::from_le_bytes([bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23]]); - let d = u64::from_le_bytes([bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31]]); + let b = u64::from_le_bytes([ + bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], + bytes[15], + ]); + let c = u64::from_le_bytes([ + bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], + bytes[23], + ]); + let d = u64::from_le_bytes([ + bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], + bytes[31], + ]); let result = (d, c, b, a); @@ -78,7 +90,7 @@ impl u256 { } /// Converts the `u256` to a sequence of big-endian bytes. - /// + /// /// # Returns /// /// * [[u8; 32]] - An array of 32 `u8` bytes that compose the `u256`. @@ -98,16 +110,19 @@ impl u256 { /// } /// ``` pub fn to_be_bytes(self) -> [u8; 32] { - let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) {r1: (u64, u64, u64, u64)}; + let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) { + r1: (u64, u64, u64, u64) + }; let a = a.to_be_bytes(); let b = b.to_be_bytes(); let c = c.to_be_bytes(); let d = d.to_be_bytes(); - let output = [a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], - b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], - c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], - d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]]; + let output = [ + a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], b[0], b[1], b[2], b[3], + b[4], b[5], b[6], b[7], c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], + ]; output } @@ -115,11 +130,11 @@ impl u256 { /// Converts a sequence of big-endian bytes to a `u256`. /// /// # Arguments - /// + /// /// * `bytes`: [[u8; 32]] - A sequence of 32 `u8` bytes that represent a `u256`. /// /// # Returns - /// + /// /// * [u256] - The resulting `u256` value. /// /// # Examples @@ -137,9 +152,18 @@ impl u256 { /// ``` pub fn from_be_bytes(bytes: [u8; 32]) -> Self { let a = u64::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]]); - let b = u64::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]]); - let c = u64::from_be_bytes([bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23]]); - let d = u64::from_be_bytes([bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31]]); + let b = u64::from_be_bytes([ + bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], + bytes[15], + ]); + let c = u64::from_be_bytes([ + bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], + bytes[23], + ]); + let d = u64::from_be_bytes([ + bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], + bytes[31], + ]); let result = (a, b, c, d); @@ -151,10 +175,11 @@ impl u256 { #[test] fn test_u256_from_le_bytes() { - let bytes = [32_u8, 31_u8, 30_u8, 29_u8, 28_u8, 27_u8, 26_u8, 25_u8, 24_u8, 23_u8, - 22_u8, 21_u8, 20_u8, 19_u8, 18_u8, 17_u8, 16_u8, 15_u8, 14_u8, 13_u8, - 12_u8, 11_u8, 10_u8, 9_u8, 8_u8, 7_u8, 6_u8, 5_u8, 4_u8, 3_u8, - 2_u8, 1_u8]; + let bytes = [ + 32_u8, 31_u8, 30_u8, 29_u8, 28_u8, 27_u8, 26_u8, 25_u8, 24_u8, 23_u8, 22_u8, + 21_u8, 20_u8, 19_u8, 18_u8, 17_u8, 16_u8, 15_u8, 14_u8, 13_u8, 12_u8, 11_u8, + 10_u8, 9_u8, 8_u8, 7_u8, 6_u8, 5_u8, 4_u8, 3_u8, 2_u8, 1_u8, + ]; let x = u256::from_le_bytes(bytes); @@ -172,15 +197,15 @@ fn test_u256_to_le_bytes() { assert(bytes[i.as_u64()] == 32_u8 - i); i += 1_u8; } - } #[test] fn test_u256_from_be_bytes() { - let bytes = [1_u8, 2_u8, 3_u8, 4_u8, 5_u8, 6_u8, 7_u8, 8_u8, 9_u8, 10_u8, - 11_u8, 12_u8, 13_u8, 14_u8, 15_u8, 16_u8, 17_u8, 18_u8, 19_u8, 20_u8, - 21_u8, 22_u8, 23_u8, 24_u8, 25_u8, 26_u8, 27_u8, 28_u8, 29_u8, 30_u8, - 31_u8, 32_u8]; + let bytes = [ + 1_u8, 2_u8, 3_u8, 4_u8, 5_u8, 6_u8, 7_u8, 8_u8, 9_u8, 10_u8, 11_u8, 12_u8, + 13_u8, 14_u8, 15_u8, 16_u8, 17_u8, 18_u8, 19_u8, 20_u8, 21_u8, 22_u8, 23_u8, + 24_u8, 25_u8, 26_u8, 27_u8, 28_u8, 29_u8, 30_u8, 31_u8, 32_u8, + ]; let x = u256::from_be_bytes(bytes); diff --git a/sway-lib-std/src/array_conversions/u32.sw b/sway-lib-std/src/array_conversions/u32.sw index 1ad40085548..5b202500c12 100644 --- a/sway-lib-std/src/array_conversions/u32.sw +++ b/sway-lib-std/src/array_conversions/u32.sw @@ -4,7 +4,7 @@ use ::assert::assert; impl u32 { /// Converts the `u32` to a sequence of little-endian bytes. - /// + /// /// # Returns /// /// * [[u8; 4]] - An array of 4 `u8` bytes that compose the `u32`. @@ -15,7 +15,7 @@ impl u32 { /// fn foo() { /// let x: u32 = 67305985; /// let result = x.to_le_bytes(); - /// + /// /// assert(result[0] == 1_u8); /// assert(result[1] == 2_u8); /// assert(result[2] == 3_u8); @@ -25,21 +25,29 @@ impl u32 { pub fn to_le_bytes(self) -> [u8; 4] { let output = [0_u8, 0_u8, 0_u8, 0_u8]; - asm(input: self, off: 0xFF, i: 0x8, j: 0x10, k: 0x18, output: output, r1) { - and r1 input off; - sb output r1 i0; - - srl r1 input i; - and r1 r1 off; - sb output r1 i1; - - srl r1 input j; - and r1 r1 off; - sb output r1 i2; - - srl r1 input k; - and r1 r1 off; - sb output r1 i3; + asm( + input: self, + off: 0xFF, + i: 0x8, + j: 0x10, + k: 0x18, + output: output, + r1, + ) { + and r1 input off; + sb output r1 i0; + + srl r1 input i; + and r1 r1 off; + sb output r1 i1; + + srl r1 input j; + and r1 r1 off; + sb output r1 i2; + + srl r1 input k; + and r1 r1 off; + sb output r1 i3; output: [u8; 4] } @@ -48,11 +56,11 @@ impl u32 { /// Converts a sequence of little-endian bytes to a `u32`. /// /// # Arguments - /// + /// /// * `bytes`: [[u8; 4]] - A sequence of 4 `u8` bytes that represent a `u32`. /// /// # Returns - /// + /// /// * [u32] - The resulting `u32` value. /// /// # Examples @@ -66,19 +74,30 @@ impl u32 { /// } /// ``` pub fn from_le_bytes(bytes: [u8; 4]) -> Self { - asm(a: bytes[0], b: bytes[1], c: bytes[2], d: bytes[3], i: 0x8, j: 0x10, k: 0x18, r1, r2, r3) { - sll r1 c j; - sll r2 d k; - or r3 r1 r2; - sll r1 b i; - or r2 a r1; - or r1 r2 r3; + asm( + a: bytes[0], + b: bytes[1], + c: bytes[2], + d: bytes[3], + i: 0x8, + j: 0x10, + k: 0x18, + r1, + r2, + r3, + ) { + sll r1 c j; + sll r2 d k; + or r3 r1 r2; + sll r1 b i; + or r2 a r1; + or r1 r2 r3; r1: u32 } } /// Converts the `u32` to a sequence of big-endian bytes. - /// + /// /// # Returns /// /// * [[u8; 4]] - An array of 4 `u8` bytes that compose the `u32`. @@ -99,21 +118,29 @@ impl u32 { pub fn to_be_bytes(self) -> [u8; 4] { let output = [0_u8, 0_u8, 0_u8, 0_u8]; - asm(input: self, off: 0xFF, i: 0x8, j: 0x10, k: 0x18, output: output, r1) { - srl r1 input k; - and r1 r1 off; - sb output r1 i0; - - srl r1 input j; - and r1 r1 off; - sb output r1 i1; - - srl r1 input i; - and r1 r1 off; - sb output r1 i2; - - and r1 input off; - sb output r1 i3; + asm( + input: self, + off: 0xFF, + i: 0x8, + j: 0x10, + k: 0x18, + output: output, + r1, + ) { + srl r1 input k; + and r1 r1 off; + sb output r1 i0; + + srl r1 input j; + and r1 r1 off; + sb output r1 i1; + + srl r1 input i; + and r1 r1 off; + sb output r1 i2; + + and r1 input off; + sb output r1 i3; output: [u8; 4] } @@ -122,11 +149,11 @@ impl u32 { /// Converts a sequence of big-endian bytes to a `u32`. /// /// # Arguments - /// + /// /// * `bytes`: [[u8; 4]] - A sequence of 4 `u8` bytes that represent a `u32`. /// /// # Returns - /// + /// /// * [u32] - The resulting `u32` value. /// /// # Examples @@ -140,13 +167,24 @@ impl u32 { /// } /// ``` pub fn from_be_bytes(bytes: [u8; 4]) -> Self { - asm(a: bytes[0], b: bytes[1], c: bytes[2], d: bytes[3], i: 0x8, j: 0x10, k: 0x18, r1, r2, r3) { - sll r1 a k; - sll r2 b j; - or r3 r1 r2; - sll r1 c i; - or r2 r3 r1; - or r1 r2 d; + asm( + a: bytes[0], + b: bytes[1], + c: bytes[2], + d: bytes[3], + i: 0x8, + j: 0x10, + k: 0x18, + r1, + r2, + r3, + ) { + sll r1 a k; + sll r2 b j; + or r3 r1 r2; + sll r1 c i; + or r2 r3 r1; + or r1 r2 d; r1: u32 } } diff --git a/sway-lib-std/src/array_conversions/u64.sw b/sway-lib-std/src/array_conversions/u64.sw index 7e55fac658a..d08b87f32ff 100644 --- a/sway-lib-std/src/array_conversions/u64.sw +++ b/sway-lib-std/src/array_conversions/u64.sw @@ -4,7 +4,7 @@ use ::assert::assert; impl u64 { /// Converts the `u64` to a sequence of little-endian bytes. - /// + /// /// # Returns /// /// * [[u8; 8]] - An array of 8 `u8` bytes that compose the `u64`. @@ -29,37 +29,49 @@ impl u64 { pub fn to_le_bytes(self) -> [u8; 8] { let output = [0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8]; - asm(input: self, off: 0xFF, i: 0x8, j: 0x10, k: 0x18, l: 0x20, m: 0x28, n: 0x30, o: 0x38, output: output, r1) { - and r1 input off; - sb output r1 i0; - - srl r1 input i; - and r1 r1 off; - sb output r1 i1; - - srl r1 input j; - and r1 r1 off; - sb output r1 i2; - - srl r1 input k; - and r1 r1 off; - sb output r1 i3; - - srl r1 input l; - and r1 r1 off; - sb output r1 i4; - - srl r1 input m; - and r1 r1 off; - sb output r1 i5; - - srl r1 input n; - and r1 r1 off; - sb output r1 i6; - - srl r1 input o; - and r1 r1 off; - sb output r1 i7; + asm( + input: self, + off: 0xFF, + i: 0x8, + j: 0x10, + k: 0x18, + l: 0x20, + m: 0x28, + n: 0x30, + o: 0x38, + output: output, + r1, + ) { + and r1 input off; + sb output r1 i0; + + srl r1 input i; + and r1 r1 off; + sb output r1 i1; + + srl r1 input j; + and r1 r1 off; + sb output r1 i2; + + srl r1 input k; + and r1 r1 off; + sb output r1 i3; + + srl r1 input l; + and r1 r1 off; + sb output r1 i4; + + srl r1 input m; + and r1 r1 off; + sb output r1 i5; + + srl r1 input n; + and r1 r1 off; + sb output r1 i6; + + srl r1 input o; + and r1 r1 off; + sb output r1 i7; output: [u8; 8] } @@ -68,11 +80,11 @@ impl u64 { /// Converts a sequence of little-endian bytes to a `u64`. /// /// # Arguments - /// + /// /// * `bytes`: [[u8; 8]] - A sequence of 8 `u8` bytes that represent a `u64`. /// /// # Returns - /// + /// /// * [u64] - The resulting `u64` value. /// /// # Examples @@ -95,28 +107,31 @@ impl u64 { let g = bytes[6]; let h = bytes[7]; - asm(a: a, b: b, c: c, d: d, e: e, f: f, g: g, h: h, i: 0x8, j: 0x10, k: 0x18, l: 0x20, m: 0x28, n: 0x30, o: 0x38, r1, r2, r3) { - sll r1 h o; - sll r2 g n; - or r3 r1 r2; - sll r1 f m; - or r2 r3 r1; - sll r3 e l; - or r1 r2 r3; - sll r2 d k; - or r3 r1 r2; - sll r1 c j; - or r2 r3 r1; - sll r3 b i; - or r1 r2 r3; - or r2 r1 a; - - r2: u64 + asm( + a: a, b: b, c: c, d: d, e: e, f: f, g: g, h: h, i: 0x8, j: 0x10, k: 0x18, + l: 0x20, m: 0x28, n: 0x30, o: 0x38, r1, r2, r3, + ) { + sll r1 h o; + sll r2 g n; + or r3 r1 r2; + sll r1 f m; + or r2 r3 r1; + sll r3 e l; + or r1 r2 r3; + sll r2 d k; + or r3 r1 r2; + sll r1 c j; + or r2 r3 r1; + sll r3 b i; + or r1 r2 r3; + or r2 r1 a; + + r2: u64 } } /// Converts the `u64` to a sequence of big-endian bytes. - /// + /// /// # Returns /// /// * [[u8; 8]] - An array of 8 `u8` bytes that compose the `u64`. @@ -141,37 +156,49 @@ impl u64 { pub fn to_be_bytes(self) -> [u8; 8] { let output = [0; 8]; - asm(input: self, off: 0xFF, i: 0x8, j: 0x10, k: 0x18, l: 0x20, m: 0x28, n: 0x30, o: 0x38, output: output, r1) { - and r1 input off; - sb output r1 i7; - - srl r1 input i; - and r1 r1 off; - sb output r1 i6; - - srl r1 input j; - and r1 r1 off; - sb output r1 i5; - - srl r1 input k; - and r1 r1 off; - sb output r1 i4; - - srl r1 input l; - and r1 r1 off; - sb output r1 i3; - - srl r1 input m; - and r1 r1 off; - sb output r1 i2; - - srl r1 input n; - and r1 r1 off; - sb output r1 i1; - - srl r1 input o; - and r1 r1 off; - sb output r1 i0; + asm( + input: self, + off: 0xFF, + i: 0x8, + j: 0x10, + k: 0x18, + l: 0x20, + m: 0x28, + n: 0x30, + o: 0x38, + output: output, + r1, + ) { + and r1 input off; + sb output r1 i7; + + srl r1 input i; + and r1 r1 off; + sb output r1 i6; + + srl r1 input j; + and r1 r1 off; + sb output r1 i5; + + srl r1 input k; + and r1 r1 off; + sb output r1 i4; + + srl r1 input l; + and r1 r1 off; + sb output r1 i3; + + srl r1 input m; + and r1 r1 off; + sb output r1 i2; + + srl r1 input n; + and r1 r1 off; + sb output r1 i1; + + srl r1 input o; + and r1 r1 off; + sb output r1 i0; output: [u8; 8] } @@ -180,11 +207,11 @@ impl u64 { /// Converts a sequence of big-endian bytes to a `u64`. /// /// # Arguments - /// + /// /// * `bytes`: [[u8; 8]] - A sequence of 8 `u8` bytes that represent a `u64`. /// /// # Returns - /// + /// /// * [u64] - The resulting `u64` value. /// /// # Examples @@ -207,21 +234,24 @@ impl u64 { let g = bytes[6]; let h = bytes[7]; - asm(a: a, b: b, c: c, d: d, e: e, f: f, g: g, h: h, i: 0x8, j: 0x10, k: 0x18, l: 0x20, m: 0x28, n: 0x30, o: 0x38, r1, r2, r3) { - sll r1 a o; - sll r2 b n; - or r3 r1 r2; - sll r1 c m; - or r2 r3 r1; - sll r3 d l; - or r1 r2 r3; - sll r2 e k; - or r3 r1 r2; - sll r1 f j; - or r2 r3 r1; - sll r3 g i; - or r1 r2 r3; - or r2 r1 h; + asm( + a: a, b: b, c: c, d: d, e: e, f: f, g: g, h: h, i: 0x8, j: 0x10, k: 0x18, + l: 0x20, m: 0x28, n: 0x30, o: 0x38, r1, r2, r3, + ) { + sll r1 a o; + sll r2 b n; + or r3 r1 r2; + sll r1 c m; + or r2 r3 r1; + sll r3 d l; + or r1 r2 r3; + sll r2 e k; + or r3 r1 r2; + sll r1 f j; + or r2 r3 r1; + sll r3 g i; + or r1 r2 r3; + or r2 r1 h; r2: u64 } diff --git a/sway-lib-std/src/assert.sw b/sway-lib-std/src/assert.sw index 5c3d28f304b..0ab81cd8568 100644 --- a/sway-lib-std/src/assert.sw +++ b/sway-lib-std/src/assert.sw @@ -3,8 +3,7 @@ library; use ::logging::log; use ::revert::revert; -use ::error_signals::{FAILED_ASSERT_SIGNAL, FAILED_ASSERT_EQ_SIGNAL, FAILED_ASSERT_NE_SIGNAL}; - +use ::error_signals::{FAILED_ASSERT_EQ_SIGNAL, FAILED_ASSERT_NE_SIGNAL, FAILED_ASSERT_SIGNAL}; /// Asserts that the given `condition` will always be `true` during runtime. /// @@ -56,7 +55,10 @@ pub fn assert(condition: bool) { /// log("a is equal to b"); /// } /// ``` -pub fn assert_eq(v1: T, v2: T) where T: Eq { +pub fn assert_eq(v1: T, v2: T) +where + T: Eq, +{ if (v1 != v2) { log(v1); log(v2); @@ -84,7 +86,10 @@ pub fn assert_eq(v1: T, v2: T) where T: Eq { /// log("a is not equal to b"); /// } /// ``` -pub fn assert_ne(v1: T, v2: T) where T: Eq { +pub fn assert_ne(v1: T, v2: T) +where + T: Eq, +{ if (v1 == v2) { log(v1); log(v2); diff --git a/sway-lib-std/src/auth.sw b/sway-lib-std/src/auth.sw index 4a38eafd4bb..fe5bb7036d4 100644 --- a/sway-lib-std/src/auth.sw +++ b/sway-lib-std/src/auth.sw @@ -6,7 +6,7 @@ use ::contract_id::ContractId; use ::identity::Identity; use ::option::Option::{self, *}; use ::result::Result::{self, *}; -use ::inputs::{Input, input_count, input_coin_owner, input_type}; +use ::inputs::{Input, input_coin_owner, input_count, input_type}; /// The error type used when an `Identity` cannot be determined. pub enum AuthError { @@ -18,20 +18,20 @@ pub enum AuthError { /// Returns `true` if the caller is external (i.e. a `script`). /// Otherwise, if the caller is a contract, returns `false`. -/// +/// /// # Additional Information -/// +/// /// For more information refer to the [VM Instruction Set](https://fuellabs.github.io/fuel-specs/master/vm/instruction_set#gm-get-metadata). /// /// # Returns -/// +/// /// * [bool] - `true` if the caller is external, `false` otherwise. -/// +/// /// # Examples /// /// ```sway /// use std::auth::caller_is_external; -/// +/// /// fn foo() { /// if caller_is_external() { /// log("Caller is external.") diff --git a/sway-lib-std/src/block.sw b/sway-lib-std/src/block.sw index bcf3ea33ed0..057992b3def 100644 --- a/sway-lib-std/src/block.sw +++ b/sway-lib-std/src/block.sw @@ -25,7 +25,7 @@ enum BlockHashError { /// /// fn foo() { /// let current_height = height(); -/// log(current_height); +/// log(current_height); /// } /// ``` pub fn height() -> u32 { @@ -97,7 +97,7 @@ pub fn timestamp_of_block(block_height: u32) -> u64 { /// Get the header hash of the block at height `block_height` /// /// # Returns -/// +/// /// * [Result] - The header hash of the block at `block_height`, or a [BlockHashError] if the block is not found. /// /// # Examples @@ -111,7 +111,6 @@ pub fn timestamp_of_block(block_height: u32) -> u64 { /// } /// ``` pub fn block_header_hash(block_height: u32) -> Result { - let mut header_hash = ZERO_B256; asm(r1: __addr_of(header_hash), r2: block_height) { @@ -129,7 +128,7 @@ pub fn block_header_hash(block_height: u32) -> Result { //////////////////////////////////////////////////////////////////// // Tests //////////////////////////////////////////////////////////////////// - + #[test(should_revert)] fn test_block_header_hash_err_current_height() { // Get the header hash of the current block. Each time this test runs, the block height will be 1. calling BHSH with a height >= current height will fail. @@ -144,7 +143,6 @@ fn test_block_header_hash_err_current_height() { #[test(should_revert)] fn test_block_header_hash_err_future_height() { - // Try to get header hash of a block in the future // The function should return a BlockHashError let hash = block_header_hash(height() + 1u32); @@ -154,5 +152,4 @@ fn test_block_header_hash_err_future_height() { }; assert(correct_error); - } diff --git a/sway-lib-std/src/bytes.sw b/sway-lib-std/src/bytes.sw index 12f9e2ce819..18379576b3c 100644 --- a/sway-lib-std/src/bytes.sw +++ b/sway-lib-std/src/bytes.sw @@ -176,10 +176,10 @@ impl Bytes { /// /// fn foo() { /// let bytes = Bytes::new(); - /// + /// /// let res = bytes.pop(); /// assert(res.is_none()); - /// + /// /// bytes.push(5); /// let res = bytes.pop(); /// assert(res.unwrap() == 5); @@ -259,11 +259,11 @@ impl Bytes { /// bytes.push(a); /// bytes.push(b); /// bytes.push(c); - /// + /// /// let d = 11u8; - /// + /// /// bytes.set(1, d); - /// + /// /// assert(bytes.len() == 3); /// assert(bytes.get(0).unwrap() == a); /// assert(bytes.get(1).unwrap() == d); @@ -305,7 +305,7 @@ impl Bytes { /// bytes.push(b); /// bytes.push(c); /// bytes.insert(1, d); - /// + /// /// assert(bytes.get(0).unwrap() == a); /// assert(bytes.get(1).unwrap() == d); /// assert(bytes.get(2).unwrap() == b); @@ -420,9 +420,9 @@ impl Bytes { /// bytes.push(a); /// bytes.push(b); /// bytes.push(c); - /// + /// /// bytes.swap(0, 1); - /// + /// /// assert(bytes.get(0).unwrap() == b); /// assert(bytes.get(1).unwrap() == a); /// assert(bytes.get(2).unwrap() == c); @@ -582,19 +582,27 @@ impl Bytes { let left_len = mid; let right_len = self.len - mid; - let mut left_bytes = Self { buf: RawBytes::with_capacity(left_len), len: left_len }; - let mut right_bytes = Self { buf: RawBytes::with_capacity(right_len), len: right_len }; + let mut left_bytes = Self { + buf: RawBytes::with_capacity(left_len), + len: left_len, + }; + let mut right_bytes = Self { + buf: RawBytes::with_capacity(right_len), + len: right_len, + }; if mid > 0 { self.buf.ptr().copy_bytes_to(left_bytes.buf.ptr(), left_len); }; if mid != self.len { - self.buf.ptr().add_uint_offset(mid).copy_bytes_to(right_bytes.buf.ptr(), right_len); + self.buf + .ptr() + .add_uint_offset(mid) + .copy_bytes_to(right_bytes.buf.ptr(), right_len); }; left_bytes.len = left_len; right_bytes.len = right_len; - (left_bytes, right_bytes) } @@ -616,13 +624,13 @@ impl Bytes { /// bytes.push(7u8); /// bytes.push(9u8); /// assert(bytes.len() == 3); - /// + /// /// let mut bytes2 = Bytes::new(); /// bytes2.push(5u8); /// bytes2.push(7u8); /// bytes2.push(9u8); /// assert(bytes2.len() == 3); - /// + /// /// let first_length = bytes.len(); /// let second_length = bytes2.len(); /// let first_cap = bytes.capacity(); @@ -653,7 +661,9 @@ impl Bytes { let mut i = 0; while i < other.len { let new_ptr = self.buf.ptr().add_uint_offset(other_start); - new_ptr.add_uint_offset(i).write_byte(other.buf.ptr.add_uint_offset(i).read_byte()); + new_ptr + .add_uint_offset(i) + .write_byte(other.buf.ptr.add_uint_offset(i).read_byte()); i += 1; } @@ -682,7 +692,9 @@ impl core::ops::Eq for Bytes { impl AsRawSlice for Bytes { /// Returns a raw slice of all of the elements in the type. fn as_raw_slice(self) -> raw_slice { - asm(ptr: (self.buf.ptr(), self.len)) { ptr: raw_slice } + asm(ptr: (self.buf.ptr(), self.len)) { + ptr: raw_slice + } } } @@ -727,7 +739,7 @@ impl From for Bytes { /// vec.push(a); /// vec.push(b); /// vec.push(c); - /// + /// /// let vec_as_raw_slice = vec.as_raw_slice(); /// let bytes = Bytes::from(vec_as_raw_slice); /// @@ -769,7 +781,9 @@ impl From for Bytes { /// assert(slice.number_of_bytes() == 3); /// ``` fn into(self) -> raw_slice { - asm(ptr: (self.buf.ptr(), self.len)) { ptr: raw_slice } + asm(ptr: (self.buf.ptr(), self.len)) { + ptr: raw_slice + } } } @@ -1194,7 +1208,6 @@ fn test_append_to_empty_bytes() { assert(bytes2.len() == 0); assert(bytes2.capacity() == 0); - } #[test()] @@ -1225,7 +1238,9 @@ fn test_eq() { #[test()] fn test_as_raw_slice() { let val = 0x3497297632836282349729763283628234972976328362823497297632836282; - let slice_1 = asm(ptr: (__addr_of(val), 32)) { ptr: raw_slice }; + let slice_1 = asm(ptr: (__addr_of(val), 32)) { + ptr: raw_slice + }; let mut bytes = Bytes::from(slice_1); let slice_2 = bytes.as_raw_slice(); assert(slice_1.ptr() == slice_2.ptr()); @@ -1236,7 +1251,9 @@ fn test_as_raw_slice() { #[test()] fn test_from_raw_slice() { let val = 0x3497297632836282349729763283628234972976328362823497297632836282; - let slice_1 = asm(ptr: (__addr_of(val), 32)) { ptr: raw_slice }; + let slice_1 = asm(ptr: (__addr_of(val), 32)) { + ptr: raw_slice + }; let mut bytes = Bytes::from(slice_1); let slice_2 = bytes.as_raw_slice(); assert(slice_1.ptr() == slice_2.ptr()); diff --git a/sway-lib-std/src/bytes_conversions/b256.sw b/sway-lib-std/src/bytes_conversions/b256.sw index d9f6a252ebb..2d9950d5601 100644 --- a/sway-lib-std/src/bytes_conversions/b256.sw +++ b/sway-lib-std/src/bytes_conversions/b256.sw @@ -8,7 +8,7 @@ use ::bytes_conversions::u64::*; impl b256 { /// Converts the `b256` to a sequence of little-endian bytes. - /// + /// /// # Returns /// /// * [Bytes] - The 32 bytes that compose the `b256`. @@ -28,29 +28,31 @@ impl b256 { /// } /// ``` pub fn to_le_bytes(self) -> Bytes { - let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) {r1: (u64, u64, u64, u64)}; + let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) { + r1: (u64, u64, u64, u64) + }; let a = a.to_le_bytes(); let b = b.to_le_bytes(); let c = c.to_le_bytes(); let d = d.to_le_bytes(); - let (mut a, mut b, mut c, mut d) = (d,c,b,a); + let (mut a, mut b, mut c, mut d) = (d, c, b, a); a.append(b); a.append(c); a.append(d); - a + a } /// Converts a sequence of little-endian bytes to a `b256`. /// /// # Arguments - /// + /// /// * `bytes`: [Bytes] - The 32 bytes that compose the `b256`. /// /// # Returns - /// + /// /// * [b256] - The resulting `b256` value. /// /// # Examples @@ -89,7 +91,7 @@ impl b256 { } /// Converts the `b256` to a sequence of big-endian bytes. - /// + /// /// # Returns /// /// * [Bytes] - The 32 bytes that compose the `b256`. @@ -115,11 +117,11 @@ impl b256 { /// Converts a sequence of big-endian bytes to a `b256`. /// /// # Arguments - /// + /// /// * `bytes`: [Bytes] - The 32 bytes that compose the `b256`. /// /// # Returns - /// + /// /// * [b256] - The resulting `b256` value. /// /// # Examples diff --git a/sway-lib-std/src/bytes_conversions/u16.sw b/sway-lib-std/src/bytes_conversions/u16.sw index 9c5a5d6e6bd..6af78bfd709 100644 --- a/sway-lib-std/src/bytes_conversions/u16.sw +++ b/sway-lib-std/src/bytes_conversions/u16.sw @@ -7,7 +7,7 @@ use ::option::Option; impl u16 { /// Converts the `u16` to a sequence of little-endian bytes. - /// + /// /// # Returns /// /// * [Bytes] - The 2 bytes that compose the `u16`. @@ -18,7 +18,7 @@ impl u16 { /// fn foo() { /// let x: u16 = 513; /// let result = x.to_le_bytes(); - /// + /// /// assert(result.get(0).unwrap() == 1_u8); /// assert(result.get(1).unwrap() == 2_u8); /// } @@ -27,14 +27,13 @@ impl u16 { let ptr = asm(input: self, off: 0xFF, i: 0x8, size: 2, ptr, r1) { aloc size; move ptr hp; - + and r1 input off; sb ptr r1 i0; srl r1 input i; and r1 r1 off; - sb ptr r1 i1; - + sb ptr r1 i1; ptr: raw_ptr }; @@ -48,7 +47,7 @@ impl u16 { /// Converts a sequence of little-endian bytes to a `u16`. /// /// # Arguments - /// + /// /// * `bytes`: [Bytes] - The 2 bytes that compose the `u16`. /// /// # Returns @@ -76,14 +75,14 @@ impl u16 { let b = (ptr.add_uint_offset(1)).read_byte(); let i = 0x8; asm(a: a, b: b, i: i, r1) { - sll r1 b i; - or r1 a r1; + sll r1 b i; + or r1 a r1; r1: u16 } } /// Converts the `u16` to a sequence of big-endian bytes. - /// + /// /// # Returns /// /// * [Bytes] - The 2 bytes that compose the `u16`. @@ -105,7 +104,7 @@ impl u16 { let ptr = asm(input: self, off: 0xFF, i: 0x8, size: 2, ptr, r1) { aloc size; move ptr hp; - + srl r1 input i; sb ptr r1 i0; @@ -118,14 +117,14 @@ impl u16 { let rs = asm(parts: (ptr, 2)) { parts: raw_slice }; - + Bytes::from(rs) } /// Converts a sequence of big-endian bytes to a `u16`. /// /// # Arguments - /// + /// /// * `bytes`: [Bytes] - The 2 bytes that compose the `u16`. /// /// # Returns @@ -153,8 +152,8 @@ impl u16 { let b = (ptr.add_uint_offset(1)).read_byte(); asm(a: a, b: b, i: 0x8, r1) { - sll r1 a i; - or r1 r1 b; + sll r1 a i; + or r1 r1 b; r1: u16 } } diff --git a/sway-lib-std/src/bytes_conversions/u256.sw b/sway-lib-std/src/bytes_conversions/u256.sw index b27dc40bf39..a07d3e97ed1 100644 --- a/sway-lib-std/src/bytes_conversions/u256.sw +++ b/sway-lib-std/src/bytes_conversions/u256.sw @@ -8,7 +8,7 @@ use ::bytes_conversions::u64::*; impl u256 { /// Converts the `u256` to a sequence of little-endian bytes. - /// + /// /// # Returns /// /// * [Bytes] - The 32 bytes that compose the `u256`. @@ -28,29 +28,31 @@ impl u256 { /// } /// ``` pub fn to_le_bytes(self) -> Bytes { - let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) {r1: (u64, u64, u64, u64)}; + let (a, b, c, d): (u64, u64, u64, u64) = asm(r1: self) { + r1: (u64, u64, u64, u64) + }; let a = a.to_le_bytes(); let b = b.to_le_bytes(); let c = c.to_le_bytes(); let d = d.to_le_bytes(); - let (mut a, mut b, mut c, mut d) = (d,c,b,a); + let (mut a, mut b, mut c, mut d) = (d, c, b, a); a.append(b); a.append(c); a.append(d); - a + a } /// Converts a sequence of little-endian bytes to a `u256`. /// /// # Arguments - /// + /// /// * `bytes`: [Bytes] - The 32 bytes that compose the `u256`. /// /// # Returns - /// + /// /// * [u256] - The resulting `u256` value. /// /// # Examples @@ -89,7 +91,7 @@ impl u256 { } /// Converts the `u256` to a sequence of big-endian bytes. - /// + /// /// # Returns /// /// * [Bytes] - The 32 bytes that compose the `u256`. @@ -109,18 +111,20 @@ impl u256 { /// } /// ``` pub fn to_be_bytes(self) -> Bytes { - let b: b256 = asm(r1: self) {r1: b256}; + let b: b256 = asm(r1: self) { + r1: b256 + }; Bytes::from(b) } /// Converts a sequence of big-endian bytes to a `u256`. /// /// # Arguments - /// + /// /// * `bytes`: [Bytes] - The 32 bytes that compose the `u256`. /// /// # Returns - /// + /// /// * [u256] - The resulting `u256` value. /// /// # Examples diff --git a/sway-lib-std/src/bytes_conversions/u32.sw b/sway-lib-std/src/bytes_conversions/u32.sw index 62b0ea2f8e1..fe7c4a18064 100644 --- a/sway-lib-std/src/bytes_conversions/u32.sw +++ b/sway-lib-std/src/bytes_conversions/u32.sw @@ -7,7 +7,7 @@ use ::option::Option; impl u32 { /// Converts the `u32` to a sequence of little-endian bytes. - /// + /// /// # Returns /// /// * [Bytes] - The 4 bytes that compose the `u32`. @@ -20,7 +20,7 @@ impl u32 { /// fn foo() { /// let x: u32 = 67305985; /// let result = x.to_le_bytes(); - /// + /// /// assert(result.get(0).unwrap() == 1_u8); /// assert(result.get(1).unwrap() == 2_u8); /// assert(result.get(2).unwrap() == 3_u8); @@ -28,10 +28,19 @@ impl u32 { /// } /// ``` pub fn to_le_bytes(self) -> Bytes { - let ptr = asm(input: self, off: 0xFF, i: 0x8, j: 0x10, k: 0x18, size: 4, ptr, r1) { + let ptr = asm( + input: self, + off: 0xFF, + i: 0x8, + j: 0x10, + k: 0x18, + size: 4, + ptr, + r1, + ) { aloc size; move ptr hp; - + and r1 input off; sb ptr r1 i0; @@ -60,7 +69,7 @@ impl u32 { /// Converts a sequence of little-endian bytes to a `u32`. /// /// # Arguments - /// + /// /// * `bytes`: [Bytes] - The 4 bytes that compose the `u32`. /// /// # Returns @@ -92,18 +101,18 @@ impl u32 { let d = (ptr.add_uint_offset(3)).read_byte(); asm(a: a, b: b, c: c, d: d, i: 0x8, j: 0x10, k: 0x18, r1, r2, r3) { - sll r1 c j; - sll r2 d k; - or r3 r1 r2; - sll r1 b i; - or r2 a r1; - or r1 r2 r3; + sll r1 c j; + sll r2 d k; + or r3 r1 r2; + sll r1 b i; + or r2 a r1; + or r1 r2 r3; r1: u32 } } /// Converts the `u32` to a sequence of big-endian bytes. - /// + /// /// # Returns /// /// * [Bytes] - The 4 bytes that compose the `u32`. @@ -124,24 +133,33 @@ impl u32 { /// } /// ``` pub fn to_be_bytes(self) -> Bytes { - let ptr = asm(input: self, off: 0xFF, i: 0x8, j: 0x10, k: 0x18, size: 4, ptr, r1) { + let ptr = asm( + input: self, + off: 0xFF, + i: 0x8, + j: 0x10, + k: 0x18, + size: 4, + ptr, + r1, + ) { aloc size; move ptr hp; - - srl r1 input k; - and r1 r1 off; - sb ptr r1 i0; - srl r1 input j; - and r1 r1 off; - sb ptr r1 i1; + srl r1 input k; + and r1 r1 off; + sb ptr r1 i0; - srl r1 input i; - and r1 r1 off; - sb ptr r1 i2; + srl r1 input j; + and r1 r1 off; + sb ptr r1 i1; - and r1 input off; - sb ptr r1 i3; + srl r1 input i; + and r1 r1 off; + sb ptr r1 i2; + + and r1 input off; + sb ptr r1 i3; ptr: raw_ptr }; @@ -149,14 +167,14 @@ impl u32 { let rs = asm(parts: (ptr, 4)) { parts: raw_slice }; - + Bytes::from(rs) } /// Converts a sequence of big-endian bytes to a `u32`. /// /// # Arguments - /// + /// /// * `bytes`: [Bytes] - The 4 bytes that compose the `u32`. /// /// # Returns @@ -188,12 +206,12 @@ impl u32 { let d = (ptr.add_uint_offset(3)).read_byte(); asm(a: a, b: b, c: c, d: d, i: 0x8, j: 0x10, k: 0x18, r1, r2, r3) { - sll r1 a k; - sll r2 b j; - or r3 r1 r2; - sll r1 c i; - or r2 r3 r1; - or r1 r2 d; + sll r1 a k; + sll r2 b j; + or r3 r1 r2; + sll r1 c i; + or r2 r3 r1; + or r1 r2 d; r1: u32 } } diff --git a/sway-lib-std/src/bytes_conversions/u64.sw b/sway-lib-std/src/bytes_conversions/u64.sw index b286166967c..bf573914550 100644 --- a/sway-lib-std/src/bytes_conversions/u64.sw +++ b/sway-lib-std/src/bytes_conversions/u64.sw @@ -7,7 +7,7 @@ use ::option::Option; impl u64 { /// Converts the `u64` to a sequence of little-endian bytes. - /// + /// /// # Returns /// /// * [Bytes] - The bytes that compose the `u64`. @@ -20,7 +20,7 @@ impl u64 { /// fn foo() { /// let x: u64 = 578437695752307201; /// let result = x.to_le_bytes(); - /// + /// /// assert(result.get(0).unwrap() == 1_u8); /// assert(result.get(1).unwrap() == 2_u8); /// assert(result.get(2).unwrap() == 3_u8); @@ -32,10 +32,23 @@ impl u64 { /// } /// ``` pub fn to_le_bytes(self) -> Bytes { - let ptr = asm(input: self, off: 0xFF, i: 0x8, j: 0x10, k: 0x18, l: 0x20, m: 0x28, n: 0x30, o: 0x38, size: 8, ptr, r1) { + let ptr = asm( + input: self, + off: 0xFF, + i: 0x8, + j: 0x10, + k: 0x18, + l: 0x20, + m: 0x28, + n: 0x30, + o: 0x38, + size: 8, + ptr, + r1, + ) { aloc size; move ptr hp; - + and r1 input off; sb ptr r1 i0; @@ -80,7 +93,7 @@ impl u64 { /// Converts a sequence of little-endian bytes to a `u64`. /// /// # Arguments - /// + /// /// * `bytes`: [Bytes] - A `Bytes` object that represent a `u64`. /// /// # Returns @@ -119,28 +132,31 @@ impl u64 { let g = (ptr.add_uint_offset(6)).read_byte(); let h = (ptr.add_uint_offset(7)).read_byte(); - asm(a: a, b: b, c: c, d: d, e: e, f: f, g: g, h: h, i: 0x8, j: 0x10, k: 0x18, l: 0x20, m: 0x28, n: 0x30, o: 0x38, r1, r2, r3) { - sll r1 h o; - sll r2 g n; - or r3 r1 r2; - sll r1 f m; - or r2 r3 r1; - sll r3 e l; - or r1 r2 r3; - sll r2 d k; - or r3 r1 r2; - sll r1 c j; - or r2 r3 r1; - sll r3 b i; - or r1 r2 r3; - or r2 r1 a; - - r2: u64 + asm( + a: a, b: b, c: c, d: d, e: e, f: f, g: g, h: h, i: 0x8, j: 0x10, k: 0x18, + l: 0x20, m: 0x28, n: 0x30, o: 0x38, r1, r2, r3, + ) { + sll r1 h o; + sll r2 g n; + or r3 r1 r2; + sll r1 f m; + or r2 r3 r1; + sll r3 e l; + or r1 r2 r3; + sll r2 d k; + or r3 r1 r2; + sll r1 c j; + or r2 r3 r1; + sll r3 b i; + or r1 r2 r3; + or r2 r1 a; + + r2: u64 } } /// Converts the `u64` to a sequence of big-endian bytes. - /// + /// /// # Returns /// /// * [Bytes] - The bytes that compose the `u64`. @@ -165,44 +181,57 @@ impl u64 { /// } /// ``` pub fn to_be_bytes(self) -> Bytes { - let ptr = asm(input: self, off: 0xFF, i: 0x8, j: 0x10, k: 0x18, l: 0x20, m: 0x28, n: 0x30, o: 0x38, size: 8, ptr, r1) { + let ptr = asm( + input: self, + off: 0xFF, + i: 0x8, + j: 0x10, + k: 0x18, + l: 0x20, + m: 0x28, + n: 0x30, + o: 0x38, + size: 8, + ptr, + r1, + ) { aloc size; move ptr hp; - and r1 input off; - sb ptr r1 i7; + and r1 input off; + sb ptr r1 i7; - srl r1 input i; - and r1 r1 off; - sb ptr r1 i6; + srl r1 input i; + and r1 r1 off; + sb ptr r1 i6; - srl r1 input j; - and r1 r1 off; - sb ptr r1 i5; + srl r1 input j; + and r1 r1 off; + sb ptr r1 i5; - srl r1 input k; - and r1 r1 off; - sb ptr r1 i4; + srl r1 input k; + and r1 r1 off; + sb ptr r1 i4; - srl r1 input l; - and r1 r1 off; - sb ptr r1 i3; + srl r1 input l; + and r1 r1 off; + sb ptr r1 i3; - srl r1 input m; - and r1 r1 off; - sb ptr r1 i2; + srl r1 input m; + and r1 r1 off; + sb ptr r1 i2; - srl r1 input n; - and r1 r1 off; - sb ptr r1 i1; + srl r1 input n; + and r1 r1 off; + sb ptr r1 i1; - srl r1 input o; - and r1 r1 off; - sb ptr r1 i0; + srl r1 input o; + and r1 r1 off; + sb ptr r1 i0; ptr: raw_ptr }; - + let rs = asm(parts: (ptr, 8)) { parts: raw_slice }; @@ -213,7 +242,7 @@ impl u64 { /// Converts a sequence of big-endian bytes to a `u64`. /// /// # Arguments - /// + /// /// * `bytes`: [Bytes] - A `Bytes` object that represent a `u64`. /// /// # Returns @@ -252,23 +281,26 @@ impl u64 { let b = (ptr.add_uint_offset(6)).read_byte(); let a = (ptr.add_uint_offset(7)).read_byte(); - asm(a: a, b: b, c: c, d: d, e: e, f: f, g: g, h: h, i: 0x8, j: 0x10, k: 0x18, l: 0x20, m: 0x28, n: 0x30, o: 0x38, r1, r2, r3) { - sll r1 h o; - sll r2 g n; - or r3 r1 r2; - sll r1 f m; - or r2 r3 r1; - sll r3 e l; - or r1 r2 r3; - sll r2 d k; - or r3 r1 r2; - sll r1 c j; - or r2 r3 r1; - sll r3 b i; - or r1 r2 r3; - or r2 r1 a; - - r2: u64 + asm( + a: a, b: b, c: c, d: d, e: e, f: f, g: g, h: h, i: 0x8, j: 0x10, k: 0x18, + l: 0x20, m: 0x28, n: 0x30, o: 0x38, r1, r2, r3, + ) { + sll r1 h o; + sll r2 g n; + or r3 r1 r2; + sll r1 f m; + or r2 r3 r1; + sll r3 e l; + or r1 r2 r3; + sll r2 d k; + or r3 r1 r2; + sll r1 c j; + or r2 r3 r1; + sll r3 b i; + or r1 r2 r3; + or r2 r1 a; + + r2: u64 } } } diff --git a/sway-lib-std/src/call_frames.sw b/sway-lib-std/src/call_frames.sw index 87bd2460369..1ffdf989709 100644 --- a/sway-lib-std/src/call_frames.sw +++ b/sway-lib-std/src/call_frames.sw @@ -25,7 +25,7 @@ const SECOND_PARAMETER_OFFSET: u64 = 74; /// /// **_Note:_** If called in an external context, this will **not** return a contract ID. /// If called externally, will actually return a pointer to the transaction ID. -/// +/// /// # Returns /// /// * [ContractId] - The contract id of this contract. @@ -42,33 +42,33 @@ const SECOND_PARAMETER_OFFSET: u64 = 74; /// } /// ``` pub fn contract_id() -> ContractId { - ContractId::from(asm() { fp: b256 }) + ContractId::from(asm() { + fp: b256 + }) } /// Get the `asset_id` of coins being sent from the current call frame. /// /// # Returns -/// +/// /// * [AssetId] - The asset included in the current call frame. /// /// # Examples /// /// ```sway /// use std::{call_frames::msg_asset_id, constants::BASE_ASSET_ID}; -/// +/// /// fn foo() { /// let asset = msg_asset_id(); /// assert(asset == BASE_ASSET_ID); /// } /// ``` pub fn msg_asset_id() -> AssetId { - AssetId { - value: { - asm(asset_id) { + AssetId { + value: { asm(asset_id) { addi asset_id fp i32; asset_id: b256 - } - } + } }, } } @@ -164,7 +164,7 @@ pub fn second_param() -> T { // Accessing arbitrary call frames by pointer // /// Get a pointer to the previous (relative to the `frame_pointer` parameter) call frame using offsets from a pointer. -/// +/// /// # Additional Information /// /// More information on data from call frames can be found in the Fuel Specs. @@ -173,7 +173,7 @@ pub fn second_param() -> T { /// # Arguments /// /// * `frame_pointer`: [raw_ptr] - The call frame reference directly before the returned call frame pointer. -/// +/// /// # Returns /// /// * [raw_ptr] - The memory location of the previous call frame data. @@ -218,5 +218,7 @@ pub fn get_previous_frame_pointer(frame_pointer: raw_ptr) -> raw_ptr { /// } /// ``` pub fn get_contract_id_from_call_frame(frame_pointer: raw_ptr) -> ContractId { - ContractId::from(asm(res, ptr: frame_pointer) { ptr: b256 }) + ContractId::from(asm(res, ptr: frame_pointer) { + ptr: b256 + }) } diff --git a/sway-lib-std/src/constants.sw b/sway-lib-std/src/constants.sw index 17fdaa604b9..938b83b6a8e 100644 --- a/sway-lib-std/src/constants.sw +++ b/sway-lib-std/src/constants.sw @@ -10,7 +10,7 @@ use ::contract_id::AssetId; /// On the Fuel network, the base asset is Ether. It is hardcoded as the 0x00..00 ContractId. /// /// # Examples -/// +/// /// ```sway /// use std::{call_frames::msg_asset_id, constants::BASE_ASSET_ID}; /// @@ -23,7 +23,7 @@ pub const BASE_ASSET_ID: AssetId = AssetId::from(ZERO_B256); /// A B256 of zero value. /// /// # Examples -/// +/// /// ```sway /// use std::{call_frames::msg_asset_id, constants::ZERO_B256}; /// @@ -36,7 +36,7 @@ pub const ZERO_B256 = 0x00000000000000000000000000000000000000000000000000000000 /// The default Sub Id for assets. /// /// # Examples -/// +/// /// ```sway /// use std::{call_frames::contract_id, constants::DEFAULT_SUB_ID}; /// diff --git a/sway-lib-std/src/context.sw b/sway-lib-std/src/context.sw index 2b761eb295d..777574e5c6c 100644 --- a/sway-lib-std/src/context.sw +++ b/sway-lib-std/src/context.sw @@ -19,7 +19,7 @@ use ::registers::balance; /// /// ```sway /// use std::{context::this_balance, constants::ZERO_B256, hash::sha256, token::mint, call_frames::contract_id}; -/// +/// /// fn foo() { /// mint(ZERO_B256, 50); /// assert(this_balance(sha256((ZERO_B256, contract_id()))) == 50); @@ -44,7 +44,7 @@ pub fn this_balance(asset_id: AssetId) -> u64 { /// /// ```sway /// use std::{context::balance_of, constants::ZERO_B256, hash::sha256, token::mint, call_frames::contract_id}; -/// +/// /// fn foo() { /// mint(ZERO_B256, 50); /// assert(balance_of(contract_id(), sha256((ZERO_B256, contract_id()))) == 50); @@ -63,11 +63,11 @@ pub fn balance_of(target: ContractId, asset_id: AssetId) -> u64 { /// /// * [u64] - The amount of tokens being sent. /// -/// # Examples -/// +/// # Examples +/// /// ```sway /// use std::context::msg_amount; -/// +/// /// fn foo() { /// assert(msg_amount() == 0); /// } diff --git a/sway-lib-std/src/contract_id.sw b/sway-lib-std/src/contract_id.sw index 6b8a00ea124..efd9a4c15bb 100644 --- a/sway-lib-std/src/contract_id.sw +++ b/sway-lib-std/src/contract_id.sw @@ -18,19 +18,19 @@ impl core::ops::Eq for ContractId { } /// Functions for casting between the `b256` and `ContractId` types. -impl From for ContractId { +impl From for ContractId { /// Casts raw `b256` data to a `ContractId`. - /// + /// /// # Arguments /// /// * `bits`: [b256] - The raw `b256` data to be casted. - /// + /// /// # Returns /// /// * [ContractId] - The newly created `ContractId` from the raw `b256`. /// /// # Examples - /// + /// /// ```sway /// use std::constants::ZERO_B256; /// @@ -42,15 +42,14 @@ impl From for ContractId { Self { value: bits } } - /// Casts a `ContractId` to raw `b256` data. - /// + /// /// # Returns /// /// * [b256] - The underlying raw `b256` data of the `ContractId`. /// /// # Examples - /// + /// /// ```sway /// use std::constants::ZERO_B256; /// @@ -72,7 +71,7 @@ impl Hash for ContractId { } } -/// An AssetId is used for interacting with an asset on the network. +/// An AssetId is used for interacting with an asset on the network. /// /// # Additional Information /// @@ -101,17 +100,17 @@ impl core::ops::Eq for AssetId { impl From for AssetId { /// Casts raw `b256` data to an `AssetId`. - /// + /// /// # Arguments /// /// * `bits`: [b256] - The raw `b256` data to be casted. - /// + /// /// # Returns /// /// * [AssetId] - The newly created `AssetId` from the raw `b256`. /// /// # Examples - /// + /// /// ```sway /// use std::constants::ZERO_B256; /// @@ -124,13 +123,13 @@ impl From for AssetId { } /// Casts an `AssetId` to raw `b256` data. - /// + /// /// # Returns /// /// * [b256] - The underlying raw `b256` data of the `AssetId`. /// /// # Examples - /// + /// /// ```sway /// use std::constants::ZERO_B256; /// @@ -166,16 +165,22 @@ impl AssetId { /// let contract_id = contract_id(); /// let sub_id = ZERO_B256; /// - /// let asset_id = AssetId::new(contract_id, sub_id); + /// let asset_id = AssetId::new(contract_id, sub_id); /// } /// ``` pub fn new(contract_id: ContractId, sub_id: SubId) -> Self { let result_buffer = 0x0000000000000000000000000000000000000000000000000000000000000000; - asm(asset_id: result_buffer, ptr: (contract_id, sub_id), bytes: 64) { + asm( + asset_id: result_buffer, + ptr: (contract_id, sub_id), + bytes: 64, + ) { s256 asset_id ptr bytes; }; - - Self { value: result_buffer } + + Self { + value: result_buffer, + } } /// Creates a new AssetId with the default SubId for the current contract. @@ -195,13 +200,24 @@ impl AssetId { /// } /// ``` pub fn default() -> Self { - let contract_id = asm() { fp: b256 }; + let contract_id = asm() { + fp: b256 + }; let result_buffer = 0x0000000000000000000000000000000000000000000000000000000000000000; - asm(asset_id: result_buffer, ptr: (contract_id, 0x0000000000000000000000000000000000000000000000000000000000000000), bytes: 64) { + asm( + asset_id: result_buffer, + ptr: ( + contract_id, + 0x0000000000000000000000000000000000000000000000000000000000000000, + ), + bytes: 64, + ) { s256 asset_id ptr bytes; }; - Self { value: result_buffer } + Self { + value: result_buffer, + } } /// The base_asset_id represents the base asset of a chain. @@ -242,7 +258,7 @@ impl ContractId { /// /// **_Note:_** If called in an external context, this will **not** return a ContractId. /// If called externally, will actually return a pointer to the Transaction Id (Wrapped in the ContractId struct). - /// + /// /// # Returns /// /// * [ContractId] - The contract id of this contract. @@ -259,7 +275,9 @@ impl ContractId { /// } /// ``` pub fn this() -> ContractId { - ContractId::from(asm() { fp: b256 }) + ContractId::from(asm() { + fp: b256 + }) } /// UNCONDITIONAL transfer of `amount` coins of type `asset_id` to /// the ContractId. @@ -327,7 +345,15 @@ impl ContractId { asm(r1: amount, r2: sub_id) { mint r1 r2; }; - self.transfer(AssetId::new(ContractId::from(asm() { fp: b256 }), sub_id), amount); + self.transfer( + AssetId::new( + ContractId::from(asm() { + fp: b256 + }), + sub_id, + ), + amount, + ); } } @@ -335,12 +361,14 @@ impl ContractId { fn test_hasher_sha256_asset_id() { use ::assert::assert; let mut hasher = Hasher::new(); - AssetId::from(0x0000000000000000000000000000000000000000000000000000000000000000).hash(hasher); + AssetId::from(0x0000000000000000000000000000000000000000000000000000000000000000) + .hash(hasher); let s256 = hasher.sha256(); assert(s256 == 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925); let mut hasher = Hasher::new(); - AssetId::from(0x0000000000000000000000000000000000000000000000000000000000000001).hash(hasher); + AssetId::from(0x0000000000000000000000000000000000000000000000000000000000000001) + .hash(hasher); let s256 = hasher.sha256(); assert(s256 == 0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5); } @@ -349,12 +377,14 @@ fn test_hasher_sha256_asset_id() { fn test_hasher_sha256_contract_id() { use ::assert::assert; let mut hasher = Hasher::new(); - ContractId::from(0x0000000000000000000000000000000000000000000000000000000000000000).hash(hasher); + ContractId::from(0x0000000000000000000000000000000000000000000000000000000000000000) + .hash(hasher); let s256 = hasher.sha256(); assert(s256 == 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925); let mut hasher = Hasher::new(); - ContractId::from(0x0000000000000000000000000000000000000000000000000000000000000001).hash(hasher); + ContractId::from(0x0000000000000000000000000000000000000000000000000000000000000001) + .hash(hasher); let s256 = hasher.sha256(); assert(s256 == 0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5); } diff --git a/sway-lib-std/src/ecr.sw b/sway-lib-std/src/ecr.sw index bf51c7c864e..81d59a9e761 100644 --- a/sway-lib-std/src/ecr.sw +++ b/sway-lib-std/src/ecr.sw @@ -43,14 +43,18 @@ pub enum EcRecoverError { /// let signature: B512 = B512::from((hi, lo)); /// // A recovered public key pair. /// let public_key = ec_recover(signature, msg_hash).unwrap(); -/// +/// /// assert(public_key.bytes[0] == pub_hi); /// assert(public_key.bytes[1] == pub_lo); /// } /// ``` pub fn ec_recover(signature: B512, msg_hash: b256) -> Result { let public_key = B512::new(); - let was_error = asm(buffer: public_key.bytes, sig: signature.bytes, hash: msg_hash) { + let was_error = asm( + buffer: public_key.bytes, + sig: signature.bytes, + hash: msg_hash, + ) { eck1 buffer sig hash; err }; @@ -92,14 +96,18 @@ pub fn ec_recover(signature: B512, msg_hash: b256) -> Result Result { let public_key = B512::new(); - let was_error = asm(buffer: public_key.bytes, sig: signature.bytes, hash: msg_hash) { + let was_error = asm( + buffer: public_key.bytes, + sig: signature.bytes, + hash: msg_hash, + ) { ecr1 buffer sig hash; err }; @@ -141,12 +149,16 @@ pub fn ec_recover_r1(signature: B512, msg_hash: b256) -> Result Result { +pub fn ed_verify( + public_key: b256, + signature: B512, + msg_hash: b256, +) -> Result { let was_error = asm(buffer: public_key, sig: signature.bytes, hash: msg_hash) { ed19 buffer sig hash; err @@ -252,7 +264,7 @@ pub fn ec_recover_address_r1(signature: B512, msg_hash: b256) -> Result Don't forget to call `enable_panic_on_overflow` or `set_flags` after performing the operations for which you disabled the default `panic-on-overflow` behavior in the first place! /// /// # Returns -/// +/// /// * [u64] - The flag prior to disabling panic on overflow. /// /// # Examples @@ -57,7 +57,7 @@ pub fn set_flags(new_flags: u64) { /// /// fn main() { /// disable_panic_on_overflow(); -/// +/// /// // Adding 1 to the max value of a u64 is considered an overflow. /// let bar = u64::max() + 1; /// @@ -70,7 +70,7 @@ pub fn set_flags(new_flags: u64) { /// /// fn foo() { /// let prior_flags = disable_panic_on_overflow(); -/// +/// /// // Adding 1 to the max value of a u64 is considered an overflow. /// let bar = u64::max() + 1; /// @@ -105,7 +105,7 @@ pub fn disable_panic_on_overflow() -> u64 { /// /// fn main() { /// disable_panic_on_overflow(); -/// +/// /// // Adding 1 to the max value of a u64 is considered an overflow. /// let bar = u64::max() + 1; /// @@ -131,7 +131,7 @@ pub fn enable_panic_on_overflow() { /// > Don't forget to call `enable_panic_on_unsafe_math` or `set_flags` after performing the operations for which you disabled the default `panic-on-unsafe-math` behavior in the first place! /// /// # Returns -/// +/// /// * [u64] - The flag prior to disabling panic on overflow. /// /// # Examples @@ -141,11 +141,11 @@ pub fn enable_panic_on_overflow() { /// /// fn main() { /// disable_panic_on_unsafe_math(); -/// +/// /// // Division by zero is considered unsafe math. -/// let bar = 1 / 0; +/// let bar = 1 / 0; /// // Error flag is set to true whenever unsafe math occurs. Here represented as 1. -/// assert(error() == 1); +/// assert(error() == 1); /// /// enable_panic_on_unsafe_math(); /// } @@ -156,11 +156,11 @@ pub fn enable_panic_on_overflow() { /// /// fn foo() { /// let prior_flags = disable_panic_on_unsafe_math(); -/// +/// /// // Division by zero is considered unsafe math. -/// let bar = 1 / 0; +/// let bar = 1 / 0; /// // Error flag is set to true whenever unsafe math occurs. Here represented as 1. -/// assert(error() == 1); +/// assert(error() == 1); /// /// set_flags(prior_flags); /// } @@ -193,11 +193,11 @@ pub fn disable_panic_on_unsafe_math() -> u64 { /// /// fn main() { /// disable_panic_on_unsafe_math(); -/// +/// /// // Division by zero is considered unsafe math. -/// let bar = 1 / 0; +/// let bar = 1 / 0; /// // Error flag is set to true whenever unsafe math occurs. Here represented as 1. -/// assert(error() == 1); +/// assert(error() == 1); /// /// enable_panic_on_unsafe_math(); /// } @@ -239,7 +239,7 @@ fn test_disable_panic_on_unsafe_math() { div r1 r2 r3; r1: u64 }; - + assert(error() == 1); enable_panic_on_unsafe_math(); diff --git a/sway-lib-std/src/hash.sw b/sway-lib-std/src/hash.sw index 482f8fcfacd..d96f52b872f 100644 --- a/sway-lib-std/src/hash.sw +++ b/sway-lib-std/src/hash.sw @@ -4,12 +4,14 @@ library; use ::bytes::*; pub struct Hasher { - bytes: Bytes + bytes: Bytes, } impl Hasher { pub fn new() -> Self { - Self { bytes: Bytes::new() } + Self { + bytes: Bytes::new(), + } } /// Writes some data into this `Hasher`. @@ -19,7 +21,11 @@ impl Hasher { pub fn sha256(self) -> b256 { let mut result_buffer = b256::min(); - asm(hash: result_buffer, ptr: self.bytes.buf.ptr, bytes: self.bytes.len) { + asm( + hash: result_buffer, + ptr: self.bytes.buf.ptr, + bytes: self.bytes.len, + ) { s256 hash ptr bytes; hash: b256 } @@ -27,7 +33,11 @@ impl Hasher { pub fn keccak256(self) -> b256 { let mut result_buffer = b256::min(); - asm(hash: result_buffer, ptr: self.bytes.buf.ptr, bytes: self.bytes.len) { + asm( + hash: result_buffer, + ptr: self.bytes.buf.ptr, + bytes: self.bytes.len, + ) { k256 hash ptr bytes; hash: b256 } @@ -52,15 +62,14 @@ impl Hasher { __assert_is_str_array::(); let str_size = __size_of_str_array::(); let str_ptr = __addr_of(s); - + let mut bytes = Bytes::with_capacity(str_size); bytes.len = str_size; str_ptr.copy_bytes_to(bytes.buf.ptr(), str_size); - + self.write(bytes); } - } pub trait Hash { @@ -81,7 +90,7 @@ impl Hash for u16 { bytes.len = 2; asm(ptr: bytes.buf.ptr(), val: self, r1) { - slli r1 val i48; + slli r1 val i48; sw ptr r1 i0; }; @@ -95,7 +104,7 @@ impl Hash for u32 { bytes.len = 4; asm(ptr: bytes.buf.ptr(), val: self, r1) { - slli r1 val i32; + slli r1 val i32; sw ptr r1 i0; }; @@ -121,9 +130,17 @@ impl Hash for b256 { let mut bytes = Bytes::with_capacity(32); // four word capacity bytes.len = 32; - let (word_1, word_2, word_3, word_4) = asm(r1: self) { r1: (u64, u64, u64, u64) }; + let (word_1, word_2, word_3, word_4) = asm(r1: self) { + r1: (u64, u64, u64, u64) + }; - asm(ptr: bytes.buf.ptr(), val_1: word_1, val_2: word_2, val_3: word_3, val_4: word_4) { + asm( + ptr: bytes.buf.ptr(), + val_1: word_1, + val_2: word_2, + val_3: word_3, + val_4: word_4, + ) { sw ptr val_1 i0; sw ptr val_2 i1; sw ptr val_3 i2; @@ -139,9 +156,17 @@ impl Hash for u256 { let mut bytes = Bytes::with_capacity(32); // four word capacity bytes.len = 32; - let (word_1, word_2, word_3, word_4) = asm(r1: self) { r1: (u64, u64, u64, u64) }; + let (word_1, word_2, word_3, word_4) = asm(r1: self) { + r1: (u64, u64, u64, u64) + }; - asm(ptr: bytes.buf.ptr(), val_1: word_1, val_2: word_2, val_3: word_3, val_4: word_4) { + asm( + ptr: bytes.buf.ptr(), + val_1: word_1, + val_2: word_2, + val_3: word_3, + val_4: word_4, + ) { sw ptr val_1 i0; sw ptr val_2 i1; sw ptr val_3 i2; @@ -176,7 +201,11 @@ impl Hash for str { } } -impl Hash for (A, B) where A: Hash, B: Hash { +impl Hash for (A, B) +where + A: Hash, + B: Hash, +{ #[inline(never)] fn hash(self, ref mut state: Hasher) { self.0.hash(state); @@ -184,7 +213,12 @@ impl Hash for (A, B) where A: Hash, B: Hash { } } -impl Hash for (A, B, C) where A: Hash, B: Hash, C: Hash { +impl Hash for (A, B, C) +where + A: Hash, + B: Hash, + C: Hash, +{ fn hash(self, ref mut state: Hasher) { self.0.hash(state); self.1.hash(state); @@ -192,7 +226,13 @@ impl Hash for (A, B, C) where A: Hash, B: Hash, C: Hash { } } -impl Hash for (A, B, C, D) where A: Hash, B: Hash, C: Hash, D: Hash { +impl Hash for (A, B, C, D) +where + A: Hash, + B: Hash, + C: Hash, + D: Hash, +{ fn hash(self, ref mut state: Hasher) { self.0.hash(state); self.1.hash(state); @@ -201,7 +241,14 @@ impl Hash for (A, B, C, D) where A: Hash, B: Hash, C: Hash, D: Hash } } -impl Hash for (A, B, C, D, E) where A: Hash, B: Hash, C: Hash, D: Hash, E: Hash { +impl Hash for (A, B, C, D, E) +where + A: Hash, + B: Hash, + C: Hash, + D: Hash, + E: Hash, +{ fn hash(self, ref mut state: Hasher) { self.0.hash(state); self.1.hash(state); @@ -211,20 +258,29 @@ impl Hash for (A, B, C, D, E) where A: Hash, B: Hash, C: Hash, D: } } -impl Hash for [T; 1] where T: Hash { +impl Hash for [T; 1] +where + T: Hash, +{ fn hash(self, ref mut state: Hasher) { self[0].hash(state); } } -impl Hash for [T; 2] where T: Hash { +impl Hash for [T; 2] +where + T: Hash, +{ fn hash(self, ref mut state: Hasher) { self[0].hash(state); self[1].hash(state); } } -impl Hash for [T; 3] where T: Hash { +impl Hash for [T; 3] +where + T: Hash, +{ fn hash(self, ref mut state: Hasher) { self[0].hash(state); self[1].hash(state); @@ -232,7 +288,10 @@ impl Hash for [T; 3] where T: Hash { } } -impl Hash for [T; 4] where T: Hash { +impl Hash for [T; 4] +where + T: Hash, +{ fn hash(self, ref mut state: Hasher) { self[0].hash(state); self[1].hash(state); @@ -241,7 +300,10 @@ impl Hash for [T; 4] where T: Hash { } } -impl Hash for [T; 5] where T: Hash { +impl Hash for [T; 5] +where + T: Hash, +{ fn hash(self, ref mut state: Hasher) { self[0].hash(state); self[1].hash(state); @@ -251,7 +313,10 @@ impl Hash for [T; 5] where T: Hash { } } -impl Hash for [T; 6] where T: Hash { +impl Hash for [T; 6] +where + T: Hash, +{ fn hash(self, ref mut state: Hasher) { self[0].hash(state); self[1].hash(state); @@ -262,7 +327,10 @@ impl Hash for [T; 6] where T: Hash { } } -impl Hash for [T; 7] where T: Hash { +impl Hash for [T; 7] +where + T: Hash, +{ fn hash(self, ref mut state: Hasher) { self[0].hash(state); self[1].hash(state); @@ -274,7 +342,10 @@ impl Hash for [T; 7] where T: Hash { } } -impl Hash for [T; 8] where T: Hash { +impl Hash for [T; 8] +where + T: Hash, +{ fn hash(self, ref mut state: Hasher) { self[0].hash(state); self[1].hash(state); @@ -287,7 +358,10 @@ impl Hash for [T; 8] where T: Hash { } } -impl Hash for [T; 9] where T: Hash { +impl Hash for [T; 9] +where + T: Hash, +{ fn hash(self, ref mut state: Hasher) { self[0].hash(state); self[1].hash(state); @@ -301,7 +375,10 @@ impl Hash for [T; 9] where T: Hash { } } -impl Hash for [T; 10] where T: Hash { +impl Hash for [T; 10] +where + T: Hash, +{ fn hash(self, ref mut state: Hasher) { self[0].hash(state); self[1].hash(state); @@ -327,7 +404,7 @@ impl Hash for [T; 10] where T: Hash { /// * [b256] - The sha-256 hash of the value. /// /// # Examples -/// +/// /// ```sway /// use std::hash::*; /// @@ -337,7 +414,10 @@ impl Hash for [T; 10] where T: Hash { /// } /// ``` #[inline(never)] -pub fn sha256(s: T) -> b256 where T: Hash { +pub fn sha256(s: T) -> b256 +where + T: Hash, +{ let mut hasher = Hasher::new(); s.hash(hasher); hasher.sha256() @@ -347,7 +427,7 @@ pub fn sha256(s: T) -> b256 where T: Hash { /// This function is specific for string arrays /// /// # Examples -/// +/// /// ```sway /// use std::hash::*; /// @@ -358,15 +438,15 @@ pub fn sha256(s: T) -> b256 where T: Hash { /// ``` #[inline(never)] pub fn sha256_str_array(param: S) -> b256 { - __assert_is_str_array::(); + __assert_is_str_array::(); let str_size = __size_of_str_array::(); let str_ptr = __addr_of(param); - + let mut bytes = Bytes::with_capacity(str_size); bytes.len = str_size; str_ptr.copy_bytes_to(bytes.buf.ptr(), str_size); - + let mut hasher = Hasher::new(); hasher.write(bytes); hasher.sha256() @@ -383,7 +463,7 @@ pub fn sha256_str_array(param: S) -> b256 { /// * [b256] - The keccak-256 hash of the value. /// /// # Examples -/// +/// /// ```sway /// use std::hash::keccak256; /// @@ -393,7 +473,10 @@ pub fn sha256_str_array(param: S) -> b256 { /// } /// ``` #[inline(never)] -pub fn keccak256(s: T) -> b256 where T: Hash { +pub fn keccak256(s: T) -> b256 +where + T: Hash, +{ let mut hasher = Hasher::new(); s.hash(hasher); hasher.keccak256() @@ -477,12 +560,14 @@ fn test_hasher_sha256_u64() { fn test_hasher_sha256_b256() { use ::assert::assert; let mut hasher = Hasher::new(); - 0x0000000000000000000000000000000000000000000000000000000000000000.hash(hasher); + 0x0000000000000000000000000000000000000000000000000000000000000000 + .hash(hasher); let sha256 = hasher.sha256(); assert(sha256 == 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925); let mut hasher = Hasher::new(); - 0x0000000000000000000000000000000000000000000000000000000000000001.hash(hasher); + 0x0000000000000000000000000000000000000000000000000000000000000001 + .hash(hasher); let sha256 = hasher.sha256(); assert(sha256 == 0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5); } @@ -491,12 +576,14 @@ fn test_hasher_sha256_b256() { fn test_hasher_sha256_u256() { use ::assert::assert; let mut hasher = Hasher::new(); - 0x0000000000000000000000000000000000000000000000000000000000000000_u256.hash(hasher); + 0x0000000000000000000000000000000000000000000000000000000000000000_u256 + .hash(hasher); let sha256 = hasher.sha256(); assert(sha256 == 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925); let mut hasher = Hasher::new(); - 0x0000000000000000000000000000000000000000000000000000000000000001_u256.hash(hasher); + 0x0000000000000000000000000000000000000000000000000000000000000001_u256 + .hash(hasher); let sha256 = hasher.sha256(); assert(sha256 == 0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5); } @@ -607,12 +694,14 @@ fn test_hasher_keccak256_u64() { fn test_hasher_keccak256_b256() { use ::assert::assert; let mut hasher = Hasher::new(); - 0x0000000000000000000000000000000000000000000000000000000000000000.hash(hasher); + 0x0000000000000000000000000000000000000000000000000000000000000000 + .hash(hasher); let keccak256 = hasher.keccak256(); assert(keccak256 == 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563); let mut hasher = Hasher::new(); - 0x0000000000000000000000000000000000000000000000000000000000000001.hash(hasher); + 0x0000000000000000000000000000000000000000000000000000000000000001 + .hash(hasher); let keccak256 = hasher.keccak256(); assert(keccak256 == 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6); } @@ -621,12 +710,14 @@ fn test_hasher_keccak256_b256() { fn test_hasher_keccak256_u256() { use ::assert::assert; let mut hasher = Hasher::new(); - 0x0000000000000000000000000000000000000000000000000000000000000000_u256.hash(hasher); + 0x0000000000000000000000000000000000000000000000000000000000000000_u256 + .hash(hasher); let keccak256 = hasher.keccak256(); assert(keccak256 == 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563); let mut hasher = Hasher::new(); - 0x0000000000000000000000000000000000000000000000000000000000000001_u256.hash(hasher); + 0x0000000000000000000000000000000000000000000000000000000000000001_u256 + .hash(hasher); let keccak256 = hasher.keccak256(); assert(keccak256 == 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6); } diff --git a/sway-lib-std/src/identity.sw b/sway-lib-std/src/identity.sw index 78356409aea..69614c1c97d 100644 --- a/sway-lib-std/src/identity.sw +++ b/sway-lib-std/src/identity.sw @@ -6,7 +6,7 @@ use ::assert::assert; use ::address::Address; use ::alias::SubId; use ::call_frames::contract_id; -use ::constants::{ZERO_B256, BASE_ASSET_ID}; +use ::constants::{BASE_ASSET_ID, ZERO_B256}; use ::contract_id::{AssetId, ContractId}; use ::hash::*; use ::option::Option::{self, *}; @@ -33,7 +33,7 @@ impl Identity { /// Returns the `Address` of the `Identity`. /// /// # Returns - /// + /// /// * [Option
] - `Some(Address)` if the underlying type is an `Address`, otherwise `None`. /// /// # Examples @@ -57,7 +57,7 @@ impl Identity { /// Returns the `ContractId` of the `Identity`. /// /// # Returns - /// + /// /// * [Option] - `Some(Contract)` if the underlying type is an `ContractId`, otherwise `None`. /// /// # Examples @@ -81,7 +81,7 @@ impl Identity { /// Returns whether the `Identity` represents an `Address`. /// /// # Returns - /// + /// /// * [bool] - Indicates whether the `Identity` holds an `Address`. /// /// # Examples @@ -104,7 +104,7 @@ impl Identity { /// Returns whether the `Identity` represents a `ContractId`. /// /// # Returns - /// + /// /// * [bool] - Indicates whether the `Identity` holds a `ContractId`. /// /// # Examples @@ -123,7 +123,7 @@ impl Identity { Self::ContractId(_) => true, } } - + /// Transfer `amount` coins of the type `asset_id` and send them /// to the Identity. /// @@ -233,4 +233,4 @@ impl Hash for Identity { }, } } -} \ No newline at end of file +} diff --git a/sway-lib-std/src/intrinsics.sw b/sway-lib-std/src/intrinsics.sw index ca80a8ea2b1..5675c6d4be9 100644 --- a/sway-lib-std/src/intrinsics.sw +++ b/sway-lib-std/src/intrinsics.sw @@ -11,7 +11,7 @@ library; /// /// ```sway /// use std::intrinsics::is_reference_type; -/// +/// /// fn foo() { /// let a = 1; /// assert(is_reference_type(a)) diff --git a/sway-lib-std/src/logging.sw b/sway-lib-std/src/logging.sw index 6d5dfcb6b38..389fb2932b7 100644 --- a/sway-lib-std/src/logging.sw +++ b/sway-lib-std/src/logging.sw @@ -4,7 +4,7 @@ library; /// Log any stack type. /// /// # Additional Information -/// +/// /// If the type is a reference type, `log` is used. /// Otherwise `logd` is used.' /// diff --git a/sway-lib-std/src/low_level_call.sw b/sway-lib-std/src/low_level_call.sw index b52fc776064..22b62384bac 100644 --- a/sway-lib-std/src/low_level_call.sw +++ b/sway-lib-std/src/low_level_call.sw @@ -64,7 +64,8 @@ fn contract_id_to_bytes(contract_id: ContractId) -> Bytes { let mut target_bytes = Bytes::with_capacity(32); target_bytes.len = 32; - __addr_of(contract_id).copy_bytes_to(target_bytes.buf.ptr, 32); + __addr_of(contract_id) + .copy_bytes_to(target_bytes.buf.ptr, 32); target_bytes } @@ -121,7 +122,7 @@ fn ptr_as_bytes(ptr: raw_ptr) -> Bytes { /// 32 byte[32] to Contract ID to call. /// 8 byte[8] param1 First parameter (function selector). /// 8 byte[8] param2 Second parameter (abi-encoded calldata: value if value type, otherwise pointer to reference type). -/// +/// /// # Arguments /// /// * `payload` : [Bytes] - The encoded payload to be called. @@ -142,7 +143,12 @@ fn ptr_as_bytes(ptr: raw_ptr) -> Bytes { /// } /// ``` fn call_with_raw_payload(payload: Bytes, call_params: CallParams) { - asm(r1: payload.buf.ptr, r2: call_params.coins, r3: call_params.asset_id, r4: call_params.gas) { + asm( + r1: payload.buf.ptr, + r2: call_params.coins, + r3: call_params.asset_id, + r4: call_params.gas, + ) { call r1 r2 r3 r4; }; } @@ -189,7 +195,11 @@ fn create_payload( 8 byte[8] param1 First parameter (function selector). 8 byte[8] param2 Second parameter (abi-encoded calldata: value if value type, otherwise pointer to reference type). */ - require(function_selector.len() == 8, "function selector must be 8 bytes"); + require( + function_selector + .len() == 8, + "function selector must be 8 bytes", + ); // let mut payload = Bytes::new().append(contract_id_to_bytes(target)).append(function_selector); let mut payload = Bytes::new(); @@ -269,5 +279,11 @@ pub fn call_with_function_selector_vec( let mut function_selector = function_selector; let mut calldata = calldata; - call_with_function_selector(target, Bytes::from(function_selector), Bytes::from(calldata), single_value_type_arg, call_params); + call_with_function_selector( + target, + Bytes::from(function_selector), + Bytes::from(calldata), + single_value_type_arg, + call_params, + ); } diff --git a/sway-lib-std/src/math.sw b/sway-lib-std/src/math.sw index 45ceb4f5d66..b0a863c457e 100644 --- a/sway-lib-std/src/math.sw +++ b/sway-lib-std/src/math.sw @@ -51,13 +51,12 @@ pub trait Power { fn pow(self, exponent: u32) -> Self; } - impl Power for u256 { /// Raises self to the power of `exponent`, using exponentiation by squaring. - /// - /// # Panics - /// - /// Panics if the result overflows the type. + /// + /// # Panics + /// + /// Panics if the result overflows the type. fn pow(self, exponent: u32) -> Self { let one = 0x0000000000000000000000000000000000000000000000000000000000000001u256; @@ -259,9 +258,13 @@ fn exponentiation_test_math_sw() { // u256 let five = 0x0000000000000000000000000000000000000000000000000000000000000005u256; - + // 5^2 = 25 = 0x19 - assert_eq(five.pow(2), 0x0000000000000000000000000000000000000000000000000000000000000019u256); + assert_eq( + five + .pow(2), + 0x0000000000000000000000000000000000000000000000000000000000000019u256, + ); // 5^28 = 0x204FCE5E3E2502611 (see https://www.wolframalpha.com/input?i=convert+5%5E28+in+hex) assert_eq(five.pow(28), 0x0000000000000000204FCE5E3E2502611u256); @@ -425,4 +428,4 @@ fn logarithmic_test_math_sw() { assert(max_u8.log(10) == 2); assert(max_u8.log(2) == 7); assert(max_u8.log2() == 7); -} \ No newline at end of file +} diff --git a/sway-lib-std/src/message.sw b/sway-lib-std/src/message.sw index 8fe365b7ed9..9dcb15386d7 100644 --- a/sway-lib-std/src/message.sw +++ b/sway-lib-std/src/message.sw @@ -22,7 +22,7 @@ use ::revert::revert; /// /// ```sway /// use std::{message::send_message, bytes::Bytes}; -/// +/// /// fn foo() { /// let recipient = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323; /// let mut bytes = Bytes::new(); @@ -41,7 +41,12 @@ pub fn send_message(recipient: b256, msg_data: Bytes, coins: u64) { msg_data_pointer = msg_data.buf.ptr; } - asm(r1: recipient_pointer, r2: msg_data_pointer, r3: size, r4: coins) { + asm( + r1: recipient_pointer, + r2: msg_data_pointer, + r3: size, + r4: coins, + ) { smo r1 r2 r3 r4; }; } @@ -62,7 +67,7 @@ pub fn send_message(recipient: b256, msg_data: Bytes, coins: u64) { /// /// ```sway /// use std::message::send_typed_message; -/// +/// /// fn foo() { /// let recipient = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323; /// send_message(recipient, "Fuel is blazingly fast", 50); diff --git a/sway-lib-std/src/option.sw b/sway-lib-std/src/option.sw index 23ec90da995..489adcc6384 100644 --- a/sway-lib-std/src/option.sw +++ b/sway-lib-std/src/option.sw @@ -87,7 +87,10 @@ pub enum Option { } // ANCHOR_END: docs_option -impl core::ops::Eq for Option where T: Eq { +impl core::ops::Eq for Option +where + T: Eq, +{ fn eq(self, other: Self) -> bool { match (self, other) { (Option::Some(a), Option::Some(b)) => a == b, @@ -107,7 +110,7 @@ impl Option { /// # Returns /// /// * [bool] - Returns `true` if the option is `Some`, otherwise `false`. - /// + /// /// # Examples /// /// ```sway @@ -155,7 +158,7 @@ impl Option { /// Returns the contained `Some` value, consuming the `self` value. /// /// # Additional Information - /// + /// /// Because this function may revert, its use is generally discouraged. /// Instead, use pattern matching and handle the `None` /// case explicitly, or call `unwrap_or`. @@ -228,7 +231,7 @@ impl Option { /// `ok_or` : `Option::ok_or` /// /// # Arguments - /// + /// /// * `err`: [E] - The error value if the option is `None`. /// /// # Returns diff --git a/sway-lib-std/src/primitive_conversions/str.sw b/sway-lib-std/src/primitive_conversions/str.sw index 7a590424a90..a6477f57657 100644 --- a/sway-lib-std/src/primitive_conversions/str.sw +++ b/sway-lib-std/src/primitive_conversions/str.sw @@ -4,7 +4,7 @@ use ::option::Option::{self, *}; impl str { pub fn try_as_str_array(self) -> Option { - __assert_is_str_array::(); + __assert_is_str_array::(); let str_size = __size_of_str_array::(); let source = self.as_ptr(); @@ -15,7 +15,7 @@ impl str { mcp dest source str_size; dest: S }; - asm (str_size: str_size) { + asm(str_size: str_size) { cfs str_size; } Some(s) @@ -33,6 +33,6 @@ fn str_slice_to_str_array() { let a = "abcd"; let b: str[4] = a.try_as_str_array().unwrap(); let c = from_str_array(b); - + assert(a == c); } diff --git a/sway-lib-std/src/primitive_conversions/u16.sw b/sway-lib-std/src/primitive_conversions/u16.sw index 1c3a0aba42f..f1524b13f6f 100644 --- a/sway-lib-std/src/primitive_conversions/u16.sw +++ b/sway-lib-std/src/primitive_conversions/u16.sw @@ -20,7 +20,9 @@ impl TryFrom for u16 { if u > u16::max().as_u32() { None } else { - Some(asm(r1: u) {r1: u16}) + Some(asm(r1: u) { + r1: u16 + }) } } } @@ -30,19 +32,29 @@ impl TryFrom for u16 { if u > u16::max().as_u64() { None } else { - Some(asm(r1: u) {r1: u16}) + Some(asm(r1: u) { + r1: u16 + }) } } } impl TryFrom for u16 { fn try_from(u: u256) -> Option { - let parts = asm(r1: u) { r1: (u64, u64, u64, u64) }; - - if parts.0 != 0 || parts.1 != 0 || parts.2 != 0 || parts.3 > u16::max().as_u64() { + let parts = asm(r1: u) { + r1: (u64, u64, u64, u64) + }; + + if parts.0 != 0 + || parts.1 != 0 + || parts.2 != 0 + || parts.3 > u16::max().as_u64() + { None } else { - Some(asm(r1: parts.3) {r1: u16}) + Some(asm(r1: parts.3) { + r1: u16 + }) } } } @@ -50,7 +62,7 @@ impl TryFrom for u16 { #[test] fn test_u16_try_from_u32() { use ::assert::assert; - + let u32_1: u32 = 2u32; let u32_2: u32 = u16::max().as_u32() + 1; @@ -66,7 +78,7 @@ fn test_u16_try_from_u32() { #[test] fn test_u16_try_from_u64() { use ::assert::assert; - + let u64_1: u64 = 2; let u64_2: u64 = u16::max().as_u64() + 1; @@ -82,7 +94,7 @@ fn test_u16_try_from_u64() { #[test] fn test_u16_try_from_u256() { use ::assert::assert; - + let u256_1: u256 = 0x0000000000000000000000000000000000000000000000000000000000000002u256; let u256_2: u256 = 0x1000000000000000000000000000000000000000000000000000000000000000u256; diff --git a/sway-lib-std/src/primitive_conversions/u32.sw b/sway-lib-std/src/primitive_conversions/u32.sw index fe6c33cf33c..0a44d8e3090 100644 --- a/sway-lib-std/src/primitive_conversions/u32.sw +++ b/sway-lib-std/src/primitive_conversions/u32.sw @@ -25,25 +25,34 @@ impl u32 { } } - impl TryFrom for u32 { fn try_from(u: u64) -> Option { if u > u32::max().as_u64() { None } else { - Some(asm(r1: u) {r1: u32}) + Some(asm(r1: u) { + r1: u32 + }) } } } impl TryFrom for u32 { fn try_from(u: u256) -> Option { - let parts = asm(r1: u) { r1: (u64, u64, u64, u64) }; + let parts = asm(r1: u) { + r1: (u64, u64, u64, u64) + }; - if parts.0 != 0 || parts.1 != 0 || parts.2 != 0 || parts.3 > u32::max().as_u64() { + if parts.0 != 0 + || parts.1 != 0 + || parts.2 != 0 + || parts.3 > u32::max().as_u64() + { None } else { - Some(asm(r1: parts.3) {r1: u32}) + Some(asm(r1: parts.3) { + r1: u32 + }) } } } @@ -51,7 +60,7 @@ impl TryFrom for u32 { #[test] fn test_u32_try_from_u64() { use ::assert::assert; - + let u64_1: u64 = 2; let u64_2: u64 = u32::max().as_u64() + 1; @@ -67,7 +76,7 @@ fn test_u32_try_from_u64() { #[test] fn test_u32_try_from_u256() { use ::assert::assert; - + let u256_1: u256 = 0x0000000000000000000000000000000000000000000000000000000000000002u256; let u256_2: u256 = 0x1000000000000000000000000000000000000000000000000000000000000000u256; diff --git a/sway-lib-std/src/primitive_conversions/u64.sw b/sway-lib-std/src/primitive_conversions/u64.sw index c7745fc778e..fc19933e197 100644 --- a/sway-lib-std/src/primitive_conversions/u64.sw +++ b/sway-lib-std/src/primitive_conversions/u64.sw @@ -23,7 +23,7 @@ impl u64 { None } } - + pub fn try_as_u32(self) -> Option { if self <= u32::max().as_u64() { Some(asm(input: self) { @@ -37,7 +37,9 @@ impl u64 { impl TryFrom for u64 { fn try_from(u: u256) -> Option { - let parts = asm(r1: u) { r1: (u64, u64, u64, u64) }; + let parts = asm(r1: u) { + r1: (u64, u64, u64, u64) + }; if parts.0 != 0 || parts.1 != 0 || parts.2 != 0 { None @@ -50,7 +52,7 @@ impl TryFrom for u64 { #[test] fn test_u64_try_from_u256() { use ::assert::assert; - + let u256_1 = 0x0000000000000000000000000000000000000000000000000000000000000002u256; let u256_2 = 0x1000000000000000000000000000000000000000000000000000000000000000u256; diff --git a/sway-lib-std/src/primitive_conversions/u8.sw b/sway-lib-std/src/primitive_conversions/u8.sw index e1ef5d86b9f..14c1eaeb560 100644 --- a/sway-lib-std/src/primitive_conversions/u8.sw +++ b/sway-lib-std/src/primitive_conversions/u8.sw @@ -8,7 +8,9 @@ impl TryFrom for u8 { if u > u8::max().as_u16() { None } else { - Some(asm(r1: u) {r1: u8}) + Some(asm(r1: u) { + r1: u8 + }) } } } @@ -18,7 +20,9 @@ impl TryFrom for u8 { if u > u8::max().as_u32() { None } else { - Some(asm(r1: u) {r1: u8}) + Some(asm(r1: u) { + r1: u8 + }) } } } @@ -28,19 +32,29 @@ impl TryFrom for u8 { if u > u8::max().as_u64() { None } else { - Some(asm(r1: u) {r1: u8}) + Some(asm(r1: u) { + r1: u8 + }) } } } impl TryFrom for u8 { fn try_from(u: u256) -> Option { - let parts = asm(r1: u) { r1: (u64, u64, u64, u64) }; - - if parts.0 != 0 || parts.1 != 0 || parts.2 != 0 || parts.3 > u8::max().as_u64() { + let parts = asm(r1: u) { + r1: (u64, u64, u64, u64) + }; + + if parts.0 != 0 + || parts.1 != 0 + || parts.2 != 0 + || parts.3 > u8::max().as_u64() + { None } else { - Some(asm(r1: parts.3) {r1: u8}) + Some(asm(r1: parts.3) { + r1: u8 + }) } } } @@ -48,7 +62,7 @@ impl TryFrom for u8 { #[test] fn test_u8_try_from_u16() { use ::assert::assert; - + let u16_1: u16 = 2u16; let u16_2: u16 = u8::max().as_u16() + 1; @@ -64,7 +78,7 @@ fn test_u8_try_from_u16() { #[test] fn test_u8_try_from_u32() { use ::assert::assert; - + let u32_1: u32 = 2u32; let u32_2: u32 = u16::max().as_u32() + 1; @@ -80,7 +94,7 @@ fn test_u8_try_from_u32() { #[test] fn test_u8_try_from_u64() { use ::assert::assert; - + let u64_1: u64 = 2; let u64_2: u64 = u16::max().as_u64() + 1; @@ -96,7 +110,7 @@ fn test_u8_try_from_u64() { #[test] fn test_u8_try_from_u256() { use ::assert::assert; - + let u256_1: u256 = 0x0000000000000000000000000000000000000000000000000000000000000002u256; let u256_2: u256 = 0x1000000000000000000000000000000000000000000000000000000000000000u256; diff --git a/sway-lib-std/src/registers.sw b/sway-lib-std/src/registers.sw index 36fc14d11cb..c13b7629aa8 100644 --- a/sway-lib-std/src/registers.sw +++ b/sway-lib-std/src/registers.sw @@ -29,7 +29,9 @@ library; /// } /// ``` pub fn overflow() -> u64 { - asm() { of } + asm() { + of + } } /// The program counter. Memory address of the current instruction. @@ -49,7 +51,9 @@ pub fn overflow() -> u64 { /// } /// ``` pub fn program_counter() -> raw_ptr { - asm() { pc: raw_ptr } + asm() { + pc: raw_ptr + } } /// Memory address of bottom of current writable stack area. @@ -69,7 +73,9 @@ pub fn program_counter() -> raw_ptr { /// } /// ``` pub fn stack_start_ptr() -> raw_ptr { - asm() { ssp: raw_ptr } + asm() { + ssp: raw_ptr + } } /// Memory address on top of current writable stack area (points to free memory). @@ -89,7 +95,9 @@ pub fn stack_start_ptr() -> raw_ptr { /// } /// ``` pub fn stack_ptr() -> raw_ptr { - asm() { sp: raw_ptr } + asm() { + sp: raw_ptr + } } /// Memory address of beginning of current call frame. @@ -109,7 +117,9 @@ pub fn stack_ptr() -> raw_ptr { /// } /// ``` pub fn frame_ptr() -> raw_ptr { - asm() { fp: raw_ptr } + asm() { + fp: raw_ptr + } } /// Memory address below the current bottom of the heap (points to free memory). @@ -129,14 +139,16 @@ pub fn frame_ptr() -> raw_ptr { /// } /// ``` pub fn heap_ptr() -> raw_ptr { - asm() { hp: raw_ptr } + asm() { + hp: raw_ptr + } } /// Error codes for particular operations. /// /// # Additional Information /// -/// Normally, if the result of an ALU operation is mathematically undefined (e.g. dividing by zero), the VM Reverts. +/// Normally, if the result of an ALU operation is mathematically undefined (e.g. dividing by zero), the VM Reverts. /// However, if the `F_UNSAFEMATH` flag is set, $err is set to `true` and execution continues. /// /// # Returns @@ -150,13 +162,15 @@ pub fn heap_ptr() -> raw_ptr { /// /// fn foo() { /// disable_panic_on_unsafe_math(); -/// let bar = 1 / 0; -/// assert(error() == 1); +/// let bar = 1 / 0; +/// assert(error() == 1); /// enable_panic_on_unsafe_math(); /// } /// ``` pub fn error() -> u64 { - asm() { err } + asm() { + err + } } /// Remaining gas globally. @@ -184,7 +198,9 @@ pub fn error() -> u64 { /// } /// ``` pub fn global_gas() -> u64 { - asm() { ggas } + asm() { + ggas + } } /// Remaining gas in the context. @@ -209,7 +225,9 @@ pub fn global_gas() -> u64 { /// } /// ``` pub fn context_gas() -> u64 { - asm() { cgas } + asm() { + cgas + } } /// Get the amount of units of `call_frames::msg_asset_id()` being sent. @@ -228,7 +246,9 @@ pub fn context_gas() -> u64 { /// } /// ``` pub fn balance() -> u64 { - asm() { bal } + asm() { + bal + } } /// Pointer to the start of the currently-executing code. @@ -248,13 +268,15 @@ pub fn balance() -> u64 { /// } /// ``` pub fn instrs_start() -> raw_ptr { - asm() { is: raw_ptr } + asm() { + is: raw_ptr + } } /// Return value or pointer. /// /// # Returns -/// +/// /// * [u64] - The value or pointer stored in the return register of the VM for the current context. /// /// # Examples @@ -268,13 +290,15 @@ pub fn instrs_start() -> raw_ptr { /// } /// ``` pub fn return_value() -> u64 { - asm() { ret } + asm() { + ret + } } /// Return value length in bytes. /// /// # Returns -/// +/// /// * [u64] - The length in bytes of the value stored in the return register of the VM for the current context. /// /// # Examples @@ -288,7 +312,9 @@ pub fn return_value() -> u64 { /// } /// ``` pub fn return_length() -> u64 { - asm() { retl } + asm() { + retl + } } /// Flags register. @@ -313,5 +339,7 @@ pub fn return_length() -> u64 { /// } /// ``` pub fn flags() -> u64 { - asm() { flag } + asm() { + flag + } } diff --git a/sway-lib-std/src/result.sw b/sway-lib-std/src/result.sw index c932f70e206..9fd3381d5d1 100644 --- a/sway-lib-std/src/result.sw +++ b/sway-lib-std/src/result.sw @@ -4,23 +4,23 @@ //! errors. It is an enum with the variants, `Ok(T)`, representing //! success and containing a value, and `Err(E)`, representing error //! and containing an error value. -//! +//! //! Functions return `Result` whenever errors are expected and recoverable. In //! the `std` crate, `Result` is most prominently used for `Identity` //! interactions and cryptographic operations. -//! +//! //! A simple function returning `Result` might be defined and used like so: -//! +//! //! ``` //! enum Version { //! Version1, //! Version2, //! } -//! +//! //! enum VersionError { //! InvalidNumber, //! } -//! +//! //! fn parse_version(version_number: u8) -> Result { //! match version_number { //! 1 => Ok(Version::Version1), @@ -29,28 +29,28 @@ //! } //! } //! ``` -//! +//! //! ### Method overview -//! +//! //! In addition to working with pattern matching, `Result` provides a variety //! of methods. -//! +//! //! ### Querying the variant -//! +//! //! The `is_ok` and `is_err` methods return `true` if the `Result` is //! `Ok` or `Err`, respectively. -//! +//! //! `is_ok` : `Result::is_ok` //! `is_err`: `Result::is_err` -//! +//! //! ### Extracting the contained value -//! +//! //! These methods extract the contained value in a `Result` when it is //! the `Ok` variant. If the `Result` is `Err`: -//! +//! //! * `unwrap` reverts. //! * `unwrap_or` returns the default provided value. -//! +//! //! `unwrap` : `Result::unwrap` //! `unwrap_or`: `Result::unwrap_or` library; diff --git a/sway-lib-std/src/storage/storable_slice.sw b/sway-lib-std/src/storage/storable_slice.sw index a1f9dd16ed6..b889cc02862 100644 --- a/sway-lib-std/src/storage/storable_slice.sw +++ b/sway-lib-std/src/storage/storable_slice.sw @@ -11,7 +11,7 @@ use ::storage::storage_api::*; /// /// * `key`: [b256] - The storage slot at which the variable will be stored. /// * `slice`: [raw_slice] - The raw_slice to be stored. -/// +/// /// # Number of Storage Accesses /// /// * Writes: `2` @@ -52,7 +52,7 @@ pub fn write_slice(key: b256, slice: raw_slice) { /// # Arguments /// /// * `key`: [b256] - The storage slot to load the value from. -/// +/// /// # Returns /// /// - [Option] - If no value was previously stored at `key`, `None` is returned. Otherwise, @@ -61,7 +61,7 @@ pub fn write_slice(key: b256, slice: raw_slice) { /// # Number of Storage Accesses /// /// * Reads: `2` -/// +/// /// # Examples /// /// ```sway @@ -86,12 +86,14 @@ pub fn read_slice(key: b256) -> Option { let ptr = alloc_bytes(number_of_slots * 32); // Load the stored slice into the pointer. let _ = __state_load_quad(sha256(key), ptr, number_of_slots); - Some(asm(ptr: (ptr, len)) { ptr: raw_slice }) + Some(asm(ptr: (ptr, len)) { + ptr: raw_slice + }) } } } -/// Clear a sequence of storage slots starting at a some key. +/// Clear a sequence of storage slots starting at a some key. /// /// # Arguments /// @@ -100,7 +102,7 @@ pub fn read_slice(key: b256) -> Option { /// # Returns /// /// * [bool] - Indicates whether all of the storage slots cleared were previously set. -/// +/// /// # Number of Storage Accesses /// /// * Reads: `1` diff --git a/sway-lib-std/src/storage/storage_api.sw b/sway-lib-std/src/storage/storage_api.sw index 3b5e1b5ea92..662d40f7713 100644 --- a/sway-lib-std/src/storage/storage_api.sw +++ b/sway-lib-std/src/storage/storage_api.sw @@ -3,7 +3,7 @@ library; use ::alloc::alloc; use ::option::Option::{self, *}; -/// Stores a stack value in storage. Will not work for heap values. +/// Stores a stack value in storage. Will not work for heap values. /// /// # Additional Information /// @@ -19,7 +19,7 @@ use ::option::Option::{self, *}; /// /// * Reads: `1` /// * Writes: `1` -/// +/// /// # Examples /// /// ```sway @@ -72,7 +72,7 @@ pub fn write(slot: b256, offset: u64, value: T) { /// # Number of Storage Accesses /// /// * Reads: `1` -/// +/// /// # Examples /// /// ```sway @@ -101,20 +101,21 @@ pub fn read(slot: b256, offset: u64) -> Option { // Read `number_of_slots * 32` bytes starting at storage slot `slot` and return an `Option` // wrapping the value stored at `result_ptr + offset` if all the slots are valid. Otherwise, // return `None`. - if __state_load_quad(offset_slot, result_ptr, number_of_slots) { + if __state_load_quad(offset_slot, result_ptr, number_of_slots) + { Some(result_ptr.add::(place_in_slot).read::()) } else { None } } -/// Clear a value starting at some slot with an offset. +/// Clear a value starting at some slot with an offset. /// /// # Arguments /// /// * `slot` - The key of the stored value that will be cleared /// * `offset` - An offset, in words, from the start of `slot`, from which the value should be cleared. -/// +/// /// # Number of Storage Accesses /// /// * Clears: `1` @@ -167,7 +168,7 @@ fn slot_calculator(slot: b256, offset: u64) -> (b256, u64, u64) { // Where in the storage slot to align `T` in order to pack word-aligned. // offset % number_words_in_slot = word_place_in_slot let place_in_slot = offset % 4; - + // Get the number of slots `T` spans based on its packed position. // ((place_in_slot * bytes_in_word) + bytes + (bytes_in_slot - 1)) >> align_to_slot = number_of_slots let number_of_slots = match __is_reference_type::() { @@ -178,6 +179,5 @@ fn slot_calculator(slot: b256, offset: u64) -> (b256, u64, u64) { // Determine which starting slot `T` will be stored based on the offset. let mut offset_slot = slot.as_u256(); offset_slot += last_slot.as_u256() - number_of_slots.as_u256(); - (offset_slot.as_b256(), number_of_slots, place_in_slot) } diff --git a/sway-lib-std/src/storage/storage_key.sw b/sway-lib-std/src/storage/storage_key.sw index 71ae74328a7..f623c9dd65c 100644 --- a/sway-lib-std/src/storage/storage_key.sw +++ b/sway-lib-std/src/storage/storage_key.sw @@ -90,7 +90,7 @@ impl StorageKey { /// }; /// /// // Writes 42 at the third word of storage slot with key 0x000...0 - /// let x = r.write(42); + /// let x = r.write(42); /// } /// ``` #[storage(read, write)] @@ -98,7 +98,7 @@ impl StorageKey { write(self.slot, self.offset, value); } - /// Clears the value at `self`. + /// Clears the value at `self`. /// /// # Number of Storage Accesses /// @@ -155,7 +155,9 @@ impl StorageKey { /// ``` pub fn new(slot: b256, offset: u64, field_id: b256) -> Self { Self { - slot, offset, field_id + slot, + offset, + field_id, } } } @@ -164,7 +166,7 @@ impl StorageKey { fn test_storage_key_new() { use ::constants::ZERO_B256; use ::assert::assert; - + let key = StorageKey::::new(ZERO_B256, 0, ZERO_B256); assert(key.slot == ZERO_B256); assert(key.offset == 0); diff --git a/sway-lib-std/src/storage/storage_map.sw b/sway-lib-std/src/storage/storage_map.sw index b166f555f1c..fbe8e0338ff 100644 --- a/sway-lib-std/src/storage/storage_map.sw +++ b/sway-lib-std/src/storage/storage_map.sw @@ -5,9 +5,15 @@ use ::storage::storage_api::*; use ::storage::storage_key::*; /// A persistent key-value pair mapping struct. -pub struct StorageMap where K: Hash {} +pub struct StorageMap +where + K: Hash, +{} -impl StorageKey> where K: Hash { +impl StorageKey> +where + K: Hash, +{ /// Inserts a key-value pair into the map. /// /// # Arguments @@ -36,7 +42,10 @@ impl StorageKey> where K: Hash { /// } /// ``` #[storage(read, write)] - pub fn insert(self, key: K, value: V) where K: Hash { + pub fn insert(self, key: K, value: V) + where + K: Hash, +{ let key = sha256((key, self.field_id)); write::(key, 0, value); } @@ -67,11 +76,14 @@ impl StorageKey> where K: Hash { /// assert(value == retrieved_value); /// } /// ``` - pub fn get(self, key: K) -> StorageKey where K: Hash { + pub fn get(self, key: K) -> StorageKey + where + K: Hash, +{ StorageKey::::new( - sha256((key, self.field_id)), - 0, - sha256((key, self.field_id)) + sha256((key, self.field_id)), + 0, + sha256((key, self.field_id)), ) } @@ -106,7 +118,10 @@ impl StorageKey> where K: Hash { /// } /// ``` #[storage(write)] - pub fn remove(self, key: K) -> bool where K: Hash { + pub fn remove(self, key: K) -> bool + where + K: Hash, +{ let key = sha256((key, self.slot)); clear::(key, 0) } diff --git a/sway-lib-std/src/storage/storage_string.sw b/sway-lib-std/src/storage/storage_string.sw index 89245055c69..48e7eb56f80 100644 --- a/sway-lib-std/src/storage/storage_string.sw +++ b/sway-lib-std/src/storage/storage_string.sw @@ -34,7 +34,7 @@ impl StorableSlice for StorageKey { /// bytes.push(7_u8); /// bytes.push(9_u8); /// let string = String::from(bytes); - /// + /// /// storage.stored_string.write_slice(string); /// } /// ``` @@ -46,7 +46,7 @@ impl StorableSlice for StorageKey { /// Constructs a `String` type from storage. /// /// # Returns - /// + /// /// * [Option] - The valid `String` stored, otherwise `None`. /// /// # Number of Storage Accesses @@ -111,7 +111,7 @@ impl StorableSlice for StorageKey { /// bytes.push(7_u8); /// bytes.push(9_u8); /// let string = String::from(bytes); - /// + /// /// storage.stored_string.write_slice(string); /// /// assert(storage.stored_string.read_slice(key).is_some()); @@ -151,7 +151,7 @@ impl StorableSlice for StorageKey { /// bytes.push(7_u8); /// bytes.push(9_u8); /// let string = String::from(bytes); - /// + /// /// assert(storage.stored_string.len() == 0) /// storage.stored_string.write_slice(string); /// assert(storage.stored_string.len() == 3); diff --git a/sway-lib-std/src/storage/storage_vec.sw b/sway-lib-std/src/storage/storage_vec.sw index 54154362fbf..660aa895b92 100644 --- a/sway-lib-std/src/storage/storage_vec.sw +++ b/sway-lib-std/src/storage/storage_vec.sw @@ -142,11 +142,7 @@ impl StorageKey> { // This StorageKey can be read by the standard storage api. // Field Id must be unique such that nested storage vecs work as they have a // __size_of() zero and will therefore always have an offset of zero. - Some(StorageKey::::new( - key, - offset, - sha256((index, key)) - )) + Some(StorageKey::::new(key, offset, sha256((index, key)))) } /// Removes the element in the given index and moves all the elements in the following indexes @@ -159,7 +155,7 @@ impl StorageKey> { /// # Arguments /// /// * `index`: [u64] - The index of the vec to remove the item from. - /// + /// /// # Returns /// /// * [V] - The element that has been removed at the index. @@ -401,7 +397,9 @@ impl StorageKey> { let read_offset = offset_calculator::(count); write::(key, write_offset, read::(key, read_offset).unwrap()); - if count == 0 { break; } + if count == 0 { + break; + } count -= 1; } @@ -532,7 +530,12 @@ impl StorageKey> { let element1_value = read::(key, element1_offset).unwrap(); - write::(key, element1_offset, read::(key, element2_offset).unwrap()); + write::( + key, + element1_offset, + read::(key, element2_offset) + .unwrap(), + ); write::(key, element2_offset, element1_value); } @@ -567,11 +570,7 @@ impl StorageKey> { let key = sha256(self.field_id); match read::(self.field_id, 0).unwrap_or(0) { 0 => None, - _ => Some(StorageKey::::new( - key, - 0, - sha256((0, key)) - )), + _ => Some(StorageKey::::new(key, 0, sha256((0, key)))), } } @@ -609,11 +608,7 @@ impl StorageKey> { 0 => None, len => { let offset = offset_calculator::(len - 1); - Some(StorageKey::::new( - key, - offset, - sha256((len - 1, key)) - )) + Some(StorageKey::::new(key, offset, sha256((len - 1, key)))) }, } } @@ -785,7 +780,7 @@ impl StorageKey> { /// This will overwrite any existing values in the `StorageVec`. /// /// # Arguments - /// + /// /// * `vec`: [Vec] - The vector to store in storage. /// /// # Number of Storage Accesses @@ -835,7 +830,7 @@ impl StorageKey> { /// Load a `Vec` from the `StorageVec`. /// /// # Returns - /// + /// /// * [Option>] - The vector constructed from storage or `None`. /// /// # Number of Storage Accesses @@ -875,7 +870,9 @@ impl StorageKey> { let ptr = alloc_bytes(number_of_slots * 32); // Load the stored slice into the pointer. let _ = __state_load_quad(sha256(self.field_id), ptr, number_of_slots); - Vec::from(asm(ptr: (ptr, bytes)) { ptr: raw_slice }) + Vec::from(asm(ptr: (ptr, bytes)) { + ptr: raw_slice + }) } } } diff --git a/sway-lib-std/src/string.sw b/sway-lib-std/src/string.sw index a99cf5bbc11..bb243a681bc 100644 --- a/sway-lib-std/src/string.sw +++ b/sway-lib-std/src/string.sw @@ -6,11 +6,10 @@ use ::convert::From; use ::hash::{Hash, Hasher}; use ::option::Option; - /// A UTF-8 encoded growable string. -/// +/// /// # Additional Information -/// +/// /// WARNING: As this type is meant to be forward compatible with UTF-8, do *not* /// add any mutation functionality or unicode input of any kind until `char` is /// implemented, codepoints are *not* guaranteed to fall on byte boundaries @@ -36,7 +35,7 @@ impl String { /// string.push(0u8); /// let bytes = string.as_bytes(); /// assert(bytes.len() == 1); - /// assert(bytes.get(0).unwrap() == 0u8); + /// assert(bytes.get(0).unwrap() == 0u8); /// } /// ``` pub fn as_bytes(self) -> Bytes { @@ -113,9 +112,7 @@ impl String { /// } /// ``` pub fn from_ascii(bytes: Bytes) -> Self { - Self { - bytes, - } + Self { bytes } } /// Converts a string slice containing ASCII encoded bytes to a `String` @@ -145,10 +142,8 @@ impl String { bytes.len = str_size; str_ptr.copy_bytes_to(bytes.buf.ptr(), str_size); - - Self { - bytes - } + + Self { bytes } } /// Returns a `bool` indicating whether the `String` is empty. @@ -238,7 +233,9 @@ impl From for String { impl AsRawSlice for String { /// Returns a raw slice to all of the elements in the string. fn as_raw_slice(self) -> raw_slice { - asm(ptr: (self.bytes.buf.ptr(), self.bytes.len)) { ptr: raw_slice } + asm(ptr: (self.bytes.buf.ptr(), self.bytes.len)) { + ptr: raw_slice + } } } @@ -250,7 +247,9 @@ impl From for String { } fn into(self) -> raw_slice { - asm(ptr: (self.bytes.buf.ptr(), self.bytes.len)) { ptr: raw_slice } + asm(ptr: (self.bytes.buf.ptr(), self.bytes.len)) { + ptr: raw_slice + } } } @@ -500,7 +499,7 @@ fn string_test_equal() { #[test] fn string_test_hash() { use ::hash::sha256; - + let mut bytes = Bytes::new(); bytes.push(0u8); diff --git a/sway-lib-std/src/token.sw b/sway-lib-std/src/token.sw index 39ae60b5ffc..ddbe04dd008 100644 --- a/sway-lib-std/src/token.sw +++ b/sway-lib-std/src/token.sw @@ -15,7 +15,7 @@ use ::outputs::{Output, output_amount, output_count, output_type}; /// `transfer_to_address`, depending on the type of `Identity`. /// /// # Additional Information -/// +/// /// If the `to` Identity is a contract, this will transfer coins to the contract even with no way to retrieve them /// (i.e: no withdrawal functionality on the receiving contract), possibly leading to /// the **_PERMANENT LOSS OF COINS_** if not used with care. @@ -47,7 +47,7 @@ pub fn mint_to(to: Identity, sub_id: SubId, amount: u64) { /// UNCONDITIONALLY to the contract at `to`. /// /// # Additional Information -/// +/// /// This will transfer coins to a contract even with no way to retrieve them /// (i.e: no withdrawal functionality on the receiving contract), possibly leading to /// the **_PERMANENT LOSS OF COINS_** if not used with care. @@ -150,7 +150,7 @@ pub fn burn(sub_id: SubId, amount: u64) { /// `transfer_to_address`, depending on the type of `Identity`. /// /// # Additional Information -/// +/// /// If the `to` Identity is a contract this may transfer coins to the contract even with no way to retrieve them /// (i.e. no withdrawal functionality on receiving contract), possibly leading /// to the **_PERMANENT LOSS OF COINS_** if not used with care. @@ -190,7 +190,7 @@ pub fn transfer(to: Identity, asset_id: AssetId, amount: u64) { /// the contract at `to`. /// /// # Additional Information -/// +/// /// This will transfer coins to a contract even with no way to retrieve them /// (i.e. no withdrawal functionality on receiving contract), possibly leading /// to the **_PERMANENT LOSS OF COINS_** if not used with care. diff --git a/sway-lib-std/src/tx.sw b/sway-lib-std/src/tx.sw index fa141c4e503..8a803a8fbd3 100644 --- a/sway-lib-std/src/tx.sw +++ b/sway-lib-std/src/tx.sw @@ -574,5 +574,7 @@ const TX_ID_OFFSET = 0; /// } /// ``` pub fn tx_id() -> b256 { - asm(ptr: TX_ID_OFFSET) { ptr: raw_ptr }.read() + asm(ptr: TX_ID_OFFSET) { + ptr: raw_ptr + }.read() } diff --git a/sway-lib-std/src/u128.sw b/sway-lib-std/src/u128.sw index 62eaf70f349..21131b36190 100644 --- a/sway-lib-std/src/u128.sw +++ b/sway-lib-std/src/u128.sw @@ -61,15 +61,15 @@ impl u64 { /// Performs addition between two `u64` values, returning a `U128`. /// /// # Additional Information - /// + /// /// Allows for addition between two `u64` values that would otherwise overflow. /// /// # Arguments - /// + /// /// * `right`: [u64] - The right-hand side of the addition. /// /// # Returns - /// + /// /// * [U128] - The result of the addition. /// /// # Examples @@ -94,17 +94,12 @@ impl u64 { }; asm(sum, overflow, left: self, right: right, result_ptr: result) { - // Add left and right. add sum left right; - // Immediately copy the overflow of the addition from `$of` into - // `overflow` so that it's not lost. move overflow of; - // Store the overflow into the first word of result. sw result_ptr overflow i0; - // Store the sum into the second word of result. sw result_ptr sum i1; }; - + set_flags(prior_flags); result @@ -144,19 +139,20 @@ impl u64 { upper: 0, lower: 0, }; - - asm(product, overflow, left: self, right: right, result_ptr: result) { - // Multiply left and right. + + asm( + product, + overflow, + left: self, + right: right, + result_ptr: result, + ) { mul product left right; - // Immediately copy the overflow of the multiplication from `$of` into - // `overflow` so that it's not lost. move overflow of; - // Store the overflow into the first word of result. sw result_ptr overflow i0; - // Store the product into the second word of result. sw result_ptr product i1; }; - + set_flags(prior_flags); result @@ -169,7 +165,7 @@ impl U128 { /// # Returns /// /// * [U128] - A new, zero value `U128`. - /// + /// /// # Examples /// /// ```sway @@ -178,7 +174,7 @@ impl U128 { /// fn foo() { /// let new_u128 = U128::new(); /// let zero_u128 = U128 { upper: 0, lower: 0 }; - /// + /// /// assert(new_u128 == zero_u128); /// } /// ``` @@ -207,12 +203,12 @@ impl U128 { /// fn foo() { /// let zero_u128 = U128 { upper: 0, lower: 0 }; /// let zero_u64 = zero_u128.as_u64().unwrap(); - /// + /// /// assert(zero_u64 == 0); - /// + /// /// let max_u128 = U128::max(); /// let result = max_u128.as_u64(); - /// + /// /// assert(result.is_err())); /// } /// ``` @@ -237,7 +233,7 @@ impl U128 { /// fn foo() { /// let min_u128 = U128::min(); /// let zero_u128 = U128 { upper: 0, lower: 0 }; - /// + /// /// assert(min_u128 == zero_u128); /// } /// ``` @@ -262,7 +258,7 @@ impl U128 { /// fn foo() { /// let max_u128 = U128::max(); /// let maxed_u128 = U128 { upper: u64::max(), lower: u64::max() }; - /// + /// /// assert(max_u128 == maxed_u128); /// } /// ``` diff --git a/sway-lib-std/src/u256.sw b/sway-lib-std/src/u256.sw index 152d3f71908..c5fd775fb33 100644 --- a/sway-lib-std/src/u256.sw +++ b/sway-lib-std/src/u256.sw @@ -159,12 +159,12 @@ impl U256 { /// fn foo() { /// let zero_u256 = U256 { a: 0, b: 0, c: 0, d: 0 }; /// let zero_u64 = zero_u256.as_u64().unwrap(); - /// + /// /// assert(zero_u64 == 0); - /// + /// /// let max_u256 = U256::max(); /// let result = U256.as_u64(); - /// + /// /// assert(result.is_err())) /// } /// ``` @@ -195,12 +195,12 @@ impl U256 { /// fn foo() { /// let zero_u256 = U256 { a: 0, b: 0, c: 0, d: 0 }; /// let zero_u128 = zero_u256.as_u128().unwrap(); - /// + /// /// assert(zero_u128 == U128 { upper: 0, lower: 0 }); - /// + /// /// let max_u256 = U256::max(); /// let result = U256.as_u64(); - /// + /// /// assert(result.is_err())) /// } /// ``` @@ -227,7 +227,7 @@ impl U256 { /// fn foo() { /// let min_u256 = U256::min(); /// let zero_u256 = U256 { a: 0, b: 0, c: 0, d: 0 }; - /// + /// /// assert(min_u256 == zero_u256); /// } /// ``` @@ -255,7 +255,7 @@ impl U256 { /// fn foo() { /// let max_u256 = U256::max(); /// let maxed_u256 = U256 { a: u64::max(), b: u64::max(), c: u64::max(), d: u64::max() }; - /// + /// /// assert(max_u256 == maxed_u256); /// } /// ``` @@ -293,18 +293,24 @@ impl U256 { impl core::ops::Ord for U256 { #[allow(deprecated)] fn gt(self, other: Self) -> bool { - self.a > other.a || - (self.a == other.a && (self.b > other.b || - (self.b == other.b && (self.c > other.c || - (self.c == other.c && self.d > other.d)))) ) - } + self.a > other.a + || (self.a == other.a + && (self.b > other.b + || (self.b == other.b + && (self.c > other.c + || (self.c == other.c + && self.d > other.d))))) + } #[allow(deprecated)] fn lt(self, other: Self) -> bool { - self.a < other.a || - (self.a == other.a && (self.b < other.b || - (self.b == other.b && (self.c < other.c || - (self.c == other.c && self.d < other.d)))) ) + self.a < other.a + || (self.a == other.a + && (self.b < other.b + || (self.b == other.b + && (self.c < other.c + || (self.c == other.c + && self.d < other.d))))) } } @@ -682,10 +688,10 @@ impl core::ops::Divide for U256 { impl Power for U256 { /// Raises self to the power of `exponent`, using exponentiation by squaring. - /// - /// # Panics - /// - /// Panics if the result overflows the type. + /// + /// # Panics + /// + /// Panics if the result overflows the type. #[allow(deprecated)] fn pow(self, exponent: u32) -> Self { let one = U256::from((0, 0, 0, 1)); @@ -714,7 +720,7 @@ impl Power for U256 { #[allow(deprecated)] fn test_five_pow_two_u256() { let five = U256::from((0, 0, 0, 5)); - + let five_pow_two = five.pow(2); assert(five_pow_two.a == 0); assert(five_pow_two.b == 0); diff --git a/sway-lib-std/src/vec.sw b/sway-lib-std/src/vec.sw index 17eac92738f..e208a3bf83c 100644 --- a/sway-lib-std/src/vec.sw +++ b/sway-lib-std/src/vec.sw @@ -13,16 +13,16 @@ struct RawVec { impl RawVec { /// Create a new `RawVec` with zero capacity. - /// + /// /// # Returns /// /// * [RawVec] - A new `RawVec` with zero capacity. - /// + /// /// # Examples - /// + /// /// ```sway /// use std::vec::RawVec; - /// + /// /// fn foo() { /// let vec = RawVec::new(); /// } @@ -37,7 +37,7 @@ impl RawVec { /// Creates a `RawVec` (on the heap) with exactly the capacity for a /// `[T; capacity]`. This is equivalent to calling `RawVec::new` when /// `capacity` is zero. - /// + /// /// # Arguments /// /// * `capacity`: [u64] - The capacity of the `RawVec`. @@ -45,12 +45,12 @@ impl RawVec { /// # Returns /// /// * [RawVec] - A new `RawVec` with zero capacity. - /// + /// /// # Examples - /// + /// /// ```sway /// use std::vec::RawVec; - /// + /// /// fn foo() { /// let vec = RawVec::with_capacity(5); /// } @@ -219,7 +219,7 @@ impl Vec { /// vec.push(5); /// let last_element = vec.pop().unwrap(); /// assert(last_element == 5); - /// } + /// } ///``` pub fn push(ref mut self, value: T) { // If there is insufficient capacity, grow the buffer. @@ -492,10 +492,10 @@ impl Vec { /// /// fn foo() { /// let vec = Vec::new(); - /// + /// /// let res = vec.pop(); /// assert(res.is_none()); - /// + /// /// vec.push(5); /// let res = vec.pop(); /// assert(res.unwrap() == 5); @@ -608,7 +608,9 @@ impl From for Vec { } fn into(self) -> raw_slice { - asm(ptr: (self.buf.ptr(), self.len)) { ptr: raw_slice } + asm(ptr: (self.buf.ptr(), self.len)) { + ptr: raw_slice + } } } diff --git a/sway-lib-std/src/vm/evm/evm_address.sw b/sway-lib-std/src/vm/evm/evm_address.sw index 7706ad08147..c0e36f553f4 100644 --- a/sway-lib-std/src/vm/evm/evm_address.sw +++ b/sway-lib-std/src/vm/evm/evm_address.sw @@ -42,4 +42,4 @@ impl Hash for EvmAddress { let Address { value } = self; value.hash(state); } -} \ No newline at end of file +} diff --git a/swayfmt/src/constants.rs b/swayfmt/src/constants.rs index 1a536cf601c..1e13cbaeb99 100644 --- a/swayfmt/src/constants.rs +++ b/swayfmt/src/constants.rs @@ -19,7 +19,7 @@ pub const DEFAULT_STRUCTURE_LIT_WIDTH: usize = 18; /// Default max width of a user-defined structure field before falling back to vertical formatting. pub const DEFAULT_STRUCTURE_VAR_WIDTH: usize = 35; /// Default Maximum width of an array literal before falling back to vertical formatting. -pub const DEFAULT_COLLECTION_WIDTH: usize = 60; +pub const DEFAULT_COLLECTION_WIDTH: usize = 80; /// Default width threshold for an array element to be considered short. pub const DEFAULT_SHORT_ARRAY_ELEM_WIDTH_THRESHOLD: usize = 10; /// Default max length of a chain to fit on a single line. diff --git a/swayfmt/src/items/item_abi/mod.rs b/swayfmt/src/items/item_abi/mod.rs index 3b8e6fa94a9..7a8dc45c9af 100644 --- a/swayfmt/src/items/item_abi/mod.rs +++ b/swayfmt/src/items/item_abi/mod.rs @@ -1,5 +1,6 @@ use crate::{ comments::{rewrite_with_comments, write_comments}, + constants::NEW_LINE, formatter::*, utils::{ map::byte_span::{ByteSpan, LeafSpans}, @@ -37,6 +38,7 @@ impl Format for ItemAbi { // abi_items for trait_item in abi_items.iter() { trait_item.format(formatted_code, formatter)?; + write!(formatted_code, "{}", NEW_LINE)?; } if abi_items.is_empty() { @@ -54,8 +56,11 @@ impl Format for ItemAbi { Self::open_curly_brace(formatted_code, formatter)?; for item in abi_defs.get().iter() { item.format(formatted_code, formatter)?; + write!(formatted_code, "{}", NEW_LINE)?; + } + if abi_defs.get().is_empty() { + write!(formatted_code, "{}", NEW_LINE)?; } - writeln!(formatted_code)?; Self::close_curly_brace(formatted_code, formatter)?; } diff --git a/swayfmt/src/items/item_impl/mod.rs b/swayfmt/src/items/item_impl/mod.rs index 777c53c01f9..164f157ba2c 100644 --- a/swayfmt/src/items/item_impl/mod.rs +++ b/swayfmt/src/items/item_impl/mod.rs @@ -1,5 +1,6 @@ use crate::{ comments::{has_comments_in_formatter, rewrite_with_comments, write_comments}, + constants::NEW_LINE, formatter::*, utils::{ map::byte_span::{ByteSpan, LeafSpans}, @@ -50,10 +51,10 @@ impl Format for ItemImpl { } else { Self::open_curly_brace(formatted_code, formatter)?; formatter.indent(); - writeln!(formatted_code)?; + write!(formatted_code, "{}", NEW_LINE)?; for item in contents.iter() { item.format(formatted_code, formatter)?; - writeln!(formatted_code)?; + write!(formatted_code, "{}", NEW_LINE)?; } Self::close_curly_brace(formatted_code, formatter)?; } diff --git a/swayfmt/src/items/item_trait/mod.rs b/swayfmt/src/items/item_trait/mod.rs index 236ddf16537..10f94eee8b4 100644 --- a/swayfmt/src/items/item_trait/mod.rs +++ b/swayfmt/src/items/item_trait/mod.rs @@ -1,5 +1,6 @@ use crate::{ comments::{rewrite_with_comments, write_comments}, + constants::NEW_LINE, formatter::*, utils::{ map::byte_span::{ByteSpan, LeafSpans}, @@ -54,8 +55,9 @@ impl Format for ItemTrait { if trait_items.is_empty() { write_comments(formatted_code, self.trait_items.span().into(), formatter)?; } else { - for item in trait_items { + for item in trait_items.iter() { item.format(formatted_code, formatter)?; + write!(formatted_code, "{}", NEW_LINE)?; } } @@ -63,11 +65,14 @@ impl Format for ItemTrait { if let Some(trait_defs) = &self.trait_defs_opt { write!(formatted_code, " ")?; Self::open_curly_brace(formatted_code, formatter)?; - for trait_items in trait_defs.get() { + for trait_items in trait_defs.get().iter() { // format `Annotated` trait_items.format(formatted_code, formatter)?; + write!(formatted_code, "{}", NEW_LINE)?; + } + if trait_defs.get().is_empty() { + write!(formatted_code, "{}", NEW_LINE)?; } - writeln!(formatted_code)?; Self::close_curly_brace(formatted_code, formatter)?; }; @@ -92,15 +97,13 @@ impl Format for ItemTraitItem { match self { ItemTraitItem::Fn(fn_decl, _) => { fn_decl.format(formatted_code, formatter)?; - writeln!(formatted_code, ";")?; + write!(formatted_code, ";")?; } ItemTraitItem::Const(const_decl, _) => { const_decl.format(formatted_code, formatter)?; - writeln!(formatted_code)?; } ItemTraitItem::Type(type_decl, _) => { type_decl.format(formatted_code, formatter)?; - writeln!(formatted_code)?; } ItemTraitItem::Error(_, _) => { return Err(FormatterError::SyntaxError); diff --git a/swayfmt/src/items/item_use/mod.rs b/swayfmt/src/items/item_use/mod.rs index 14b8264372d..ce304183495 100644 --- a/swayfmt/src/items/item_use/mod.rs +++ b/swayfmt/src/items/item_use/mod.rs @@ -91,7 +91,17 @@ impl Format for UseTree { ord_vec.push(buf); } - ord_vec.sort_by_key(|x| x.to_lowercase()); + ord_vec.sort_by(|a, b| { + if a == b { + std::cmp::Ordering::Equal + } else if a == "self" || b == "*" { + std::cmp::Ordering::Less + } else if b == "self" || a == "*" { + std::cmp::Ordering::Greater + } else { + a.to_lowercase().cmp(&b.to_lowercase()) + } + }); for (use_tree, comma) in ord_vec.iter_mut().zip(commas.iter()) { write!(use_tree, "{}", comma.span().as_str())?; } diff --git a/swayfmt/src/utils/language/expr/mod.rs b/swayfmt/src/utils/language/expr/mod.rs index 69114cf9cfa..c11e7808122 100644 --- a/swayfmt/src/utils/language/expr/mod.rs +++ b/swayfmt/src/utils/language/expr/mod.rs @@ -748,6 +748,7 @@ fn same_line_if_only_argument(expr: &Expr) -> bool { expr, Expr::Struct { path: _, fields: _ } | Expr::Tuple(_) + | Expr::Array(_) | Expr::Parens(_) | Expr::Not { bang_token: _, diff --git a/swayfmt/src/utils/language/expr/tests.rs b/swayfmt/src/utils/language/expr/tests.rs index 9bbfaedf889..ef84d8b0c61 100644 --- a/swayfmt/src/utils/language/expr/tests.rs +++ b/swayfmt/src/utils/language/expr/tests.rs @@ -172,14 +172,14 @@ quux();\n }\n\n\n}" fmt_test_expr!( match_branch_kind_tuple_long "match (foo, bar) { ( - VeryLongFoo::SomeLongFoo(some_foo), - VeryLongBar::SomeLongBar(some_bar), + SomeVeryVeryLongFoo::SomeLongFoo(some_foo), + SomeVeryVeryLongBar::SomeLongBar(some_bar), ) => { foo(); } ( - VeryLongFoo::OtherLongFoo(other_foo), - VeryLongBar::OtherLongBar(other_bar), + SomeVeryVeryLongFoo::OtherLongFoo(other_foo), + SomeVeryVeryLongBar::OtherLongBar(other_bar), ) => { bar(); } @@ -190,12 +190,12 @@ fmt_test_expr!( match_branch_kind_tuple_long intermediate_whitespace "match (foo, bar) { ( - VeryLongFoo::SomeLongFoo(some_foo), \n \n VeryLongBar::SomeLongBar(some_bar)) => \n + SomeVeryVeryLongFoo::SomeLongFoo(some_foo), \n \n SomeVeryVeryLongBar::SomeLongBar(some_bar)) => \n \n{ \n foo(); } - (VeryLongFoo::OtherLongFoo(other_foo), VeryLongBar::OtherLongBar(other_bar) \n ) => { + (SomeVeryVeryLongFoo::OtherLongFoo(other_foo), SomeVeryVeryLongBar::OtherLongBar(other_bar) \n ) => { bar(); \n } diff --git a/swayfmt/tests/mod.rs b/swayfmt/tests/mod.rs index e6c0faa3ffe..3ae81445ed9 100644 --- a/swayfmt/tests/mod.rs +++ b/swayfmt/tests/mod.rs @@ -1797,8 +1797,8 @@ fn test() { .quux([1, 2]) .yet_another_call( [ - 1, 2, 3, 4, 6, 7, 7, 8, 8, 9, 9, 9, 19, 1123123, - 12312, 312, 312, 3123, 12, 31, 44, + 1, 2, 3, 4, 6, 7, 7, 8, 8, 9, 9, 9, 19, 1123123, 12312, 312, 312, + 3123, 12, 31, 44, ], [1, 2], true, @@ -1906,13 +1906,13 @@ fn long_array() { check( r#"library; fn main() { - let x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22]; + let x = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,99,22]; }"#, r#"library; fn main() { let x = [ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 99, 22, ]; } "#, @@ -2175,7 +2175,7 @@ fn single_long_arg() { fn main() { if foo { // ANCHOR: storage_map_insert - let addr1 = Address::from(0x0101010101010101010101010101010101010101010101010101010101010101); + let addr1 = Address::from(0x010101010101010101010101010101010101010101010101010101010101010101010101010101); } } "#, @@ -2185,7 +2185,7 @@ fn main() { if foo { // ANCHOR: storage_map_insert let addr1 = Address::from( - 0x0101010101010101010101010101010101010101010101010101010101010101, + 0x010101010101010101010101010101010101010101010101010101010101010101010101010101, ); } } @@ -2687,3 +2687,156 @@ fn test() { "#, ); } + +#[test] +fn use_sorting_items() { + check( + r#"library; + + use ::option::Option::{*, self, z, foo, bar}; +"#, + r#"library; + +use ::option::Option::{self, bar, foo, z, *}; +"#, + ); +} + +#[test] +fn whitespace_after_doccomment() { + check( + r#"library; + +/// Trait to evaluate if one value is greater than or equal, or less than or equal to another of the same type. +trait OrdEq: Ord + Eq { +} { + /// Evaluates if one value of the same type is greater or equal to than another. + /// + /// # Additional Information + /// + /// This trait requires that the `Ord` and `Eq` traits are implemented. + /// + /// # Arguments + /// + /// * `other`: [Self] - The value of the same type. + /// + /// # Returns + /// + /// * [bool] - `true` if `self` is greater than or equal to `other`, otherwise `false`. + /// + /// # Examples + /// + /// ```sway + /// struct MyStruct { + /// val: u64, + /// } + /// + /// impl Eq for MyStruct { + /// fn eq(self, other: Self) -> bool { + /// self.val == other.val + /// } + /// } + /// + /// impl Ord for MyStruct { + /// fn gt(self, other: Self) -> bool { + /// self.val > other.val + /// } + /// } + /// + /// impl OrdEq for MyStruct {} + /// + /// fn foo() { + /// let struct1 = MyStruct { val: 10 }; + /// let struct2 = MyStruct { val: 10 }; + /// let result = struct1 >= struct2; + /// assert(result); + /// } + /// ``` + fn ge(self, other: Self) -> bool { + self.gt(other) || self.eq(other) + } + /// Some test + fn test() { + + } +} + "#, + r#"library; + +/// Trait to evaluate if one value is greater than or equal, or less than or equal to another of the same type. +trait OrdEq: Ord + Eq { +} { + /// Evaluates if one value of the same type is greater or equal to than another. + /// + /// # Additional Information + /// + /// This trait requires that the `Ord` and `Eq` traits are implemented. + /// + /// # Arguments + /// + /// * `other`: [Self] - The value of the same type. + /// + /// # Returns + /// + /// * [bool] - `true` if `self` is greater than or equal to `other`, otherwise `false`. + /// + /// # Examples + /// + /// ```sway + /// struct MyStruct { + /// val: u64, + /// } + /// + /// impl Eq for MyStruct { + /// fn eq(self, other: Self) -> bool { + /// self.val == other.val + /// } + /// } + /// + /// impl Ord for MyStruct { + /// fn gt(self, other: Self) -> bool { + /// self.val > other.val + /// } + /// } + /// + /// impl OrdEq for MyStruct {} + /// + /// fn foo() { + /// let struct1 = MyStruct { val: 10 }; + /// let struct2 = MyStruct { val: 10 }; + /// let result = struct1 >= struct2; + /// assert(result); + /// } + /// ``` + fn ge(self, other: Self) -> bool { + self.gt(other) || self.eq(other) + } + /// Some test + fn test() {} +} +"#, + ); +} + +#[test] +fn single_argument_method() { + check( + r#"library; + + pub fn from_be_bytes(bytes: [u8; 32]) -> Self { + let a = u64::from_be_bytes( + [ + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], + bytes[5], bytes[6], bytes[7], + ], + ); + } + "#, + r#"library; + +pub fn from_be_bytes(bytes: [u8; 32]) -> Self { + let a = u64::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]]); +} +"#, + ); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/trait_cannot_find_in_scope_issue/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/trait_cannot_find_in_scope_issue/test.toml index 2add9ddfcea..b3397f3a95e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/trait_cannot_find_in_scope_issue/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/trait_cannot_find_in_scope_issue/test.toml @@ -4,7 +4,7 @@ category = "fail" #check: $()let _ = sha256(123u8); #nextln: $()Trait "Hash" is not imported into "main.sw" when calling "sha256". #check: $()Import the "Hash" trait into "main.sw" by using: `use std::hash::Hash;`. -#check: $()pub fn sha256(s: T) -> b256 where T: Hash { +#check: $()T: Hash, #nextln: $()In the definition of "sha256", "Hash" is used in this trait constraint. #check: $()Trait is not imported From f1226936788f95418ef8a191f49731d2b3e3690d Mon Sep 17 00:00:00 2001 From: Cameron Carstens <54727135+bitzoic@users.noreply.github.com> Date: Wed, 3 Jan 2024 11:15:32 -0500 Subject: [PATCH 6/9] Introduce `predicate_id()` to the std-lib (#5425) ## Description A predicate's address can be accessed internally from within a predicate. This functionality has been added to the std-lib with the `predicate_id()` function. Closes https://github.com/FuelLabs/sway/issues/5411 ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> --- sway-lib-std/src/auth.sw | 31 +++++ test/src/sdk-harness/Forc.lock | 5 + test/src/sdk-harness/Forc.toml | 1 + .../test_artifacts/auth_predicate/.gitignore | 2 + .../test_artifacts/auth_predicate/Forc.lock | 13 ++ .../test_artifacts/auth_predicate/Forc.toml | 8 ++ .../test_artifacts/auth_predicate/src/main.sw | 8 ++ .../src/sdk-harness/test_projects/auth/mod.rs | 115 +++++++++++++++++- 8 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 test/src/sdk-harness/test_artifacts/auth_predicate/.gitignore create mode 100644 test/src/sdk-harness/test_artifacts/auth_predicate/Forc.lock create mode 100644 test/src/sdk-harness/test_artifacts/auth_predicate/Forc.toml create mode 100644 test/src/sdk-harness/test_artifacts/auth_predicate/src/main.sw diff --git a/sway-lib-std/src/auth.sw b/sway-lib-std/src/auth.sw index fe5bb7036d4..8c2812a2fdc 100644 --- a/sway-lib-std/src/auth.sw +++ b/sway-lib-std/src/auth.sw @@ -177,3 +177,34 @@ pub fn caller_address() -> Result { None => Err(AuthError::CallerIsInternal), } } + +/// Get the current predicate's id when called in an internal context. +/// +/// # Returns +/// +/// * [Address] - The address of this predicate. +/// +/// # Reverts +/// +/// * When called outside of a predicate program. +/// +/// # Examples +/// +/// ```sway +/// use std::auth::predicate_id; +/// +/// fn main() { +/// let this_predicate = predicate_id(); +/// log(this_predicate); +/// } +/// ``` +pub fn predicate_id() -> Address { + // Get index of current predicate. + // i3 = GM_GET_VERIFYING_PREDICATE + let predicate_index = asm(r1) { + gm r1 i3; + r1: u64 + }; + + input_coin_owner(predicate_index).unwrap() +} diff --git a/test/src/sdk-harness/Forc.lock b/test/src/sdk-harness/Forc.lock index a2c5918f06c..be2acc2a855 100644 --- a/test/src/sdk-harness/Forc.lock +++ b/test/src/sdk-harness/Forc.lock @@ -18,6 +18,11 @@ dependencies = [ "std", ] +[[package]] +name = "auth_predicate" +source = "member" +dependencies = ["std"] + [[package]] name = "auth_testing_abi" source = "member" diff --git a/test/src/sdk-harness/Forc.toml b/test/src/sdk-harness/Forc.toml index 622bfa856aa..97492803ba8 100644 --- a/test/src/sdk-harness/Forc.toml +++ b/test/src/sdk-harness/Forc.toml @@ -43,6 +43,7 @@ members = [ "test_projects/vec_in_abi", "test_artifacts/auth_caller_contract", "test_artifacts/auth_caller_script", + "test_artifacts/auth_predicate", "test_artifacts/auth_testing_abi", "test_artifacts/auth_testing_contract", "test_artifacts/balance_contract", diff --git a/test/src/sdk-harness/test_artifacts/auth_predicate/.gitignore b/test/src/sdk-harness/test_artifacts/auth_predicate/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/auth_predicate/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/sdk-harness/test_artifacts/auth_predicate/Forc.lock b/test/src/sdk-harness/test_artifacts/auth_predicate/Forc.lock new file mode 100644 index 00000000000..5891443f703 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/auth_predicate/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "auth_predicate" +source = "member" +dependencies = ["std"] + +[[package]] +name = "core" +source = "path+from-root-7FCE6F17DDEC6CE9" + +[[package]] +name = "std" +source = "path+from-root-7FCE6F17DDEC6CE9" +dependencies = ["core"] diff --git a/test/src/sdk-harness/test_artifacts/auth_predicate/Forc.toml b/test/src/sdk-harness/test_artifacts/auth_predicate/Forc.toml new file mode 100644 index 00000000000..8d05fa1d23d --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/auth_predicate/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "auth_predicate" + +[dependencies] +std = { path = "../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_artifacts/auth_predicate/src/main.sw b/test/src/sdk-harness/test_artifacts/auth_predicate/src/main.sw new file mode 100644 index 00000000000..38b2f6db4e9 --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/auth_predicate/src/main.sw @@ -0,0 +1,8 @@ +predicate; + +use std::auth::predicate_id; + +fn main(predicate_address: Address) -> bool { + predicate_address == predicate_id() +} + diff --git a/test/src/sdk-harness/test_projects/auth/mod.rs b/test/src/sdk-harness/test_projects/auth/mod.rs index 68e32a5493d..0bad6d9a3ad 100644 --- a/test/src/sdk-harness/test_projects/auth/mod.rs +++ b/test/src/sdk-harness/test_projects/auth/mod.rs @@ -1,8 +1,9 @@ use fuels::{ - accounts::wallet::{Wallet, WalletUnlocked}, + accounts::{wallet::{Wallet, WalletUnlocked}, predicate::Predicate}, prelude::*, types::ContractId, }; +use std::str::FromStr; abigen!( Contract( @@ -12,7 +13,11 @@ abigen!( Contract( name = "AuthCallerContract", abi = "test_artifacts/auth_caller_contract/out/debug/auth_caller_contract-abi.json" - ) + ), + Predicate( + name = "AuthPredicate", + abi = "test_artifacts/auth_predicate/out/debug/auth_predicate-abi.json" + ), ); #[tokio::test] @@ -94,3 +99,109 @@ async fn get_contracts() -> ( wallet.lock(), ) } + +#[tokio::test] +async fn can_get_predicate_id() { + // Setup Wallets + let asset_id = AssetId::default(); + let wallets_config = WalletsConfig::new_multiple_assets( + 2, + vec![AssetConfig { + id: asset_id, + num_coins: 1, + coin_amount: 1_000, + }], + ); + let wallets = &launch_custom_provider_and_get_wallets(wallets_config, None, None).await.unwrap(); + let first_wallet = &wallets[0]; + let second_wallet = &wallets[1]; + + // Setup Predciate + let hex_predicate_address: &str = "0x76bae6a88c3f54a9aee40ee5390696dd9edaf1b2a16d96a75adbcaac2ec6584f"; + let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string"); + let predicate_bech32_address = Bech32Address::from(predicate_address); + let predicate_data = AuthPredicateEncoder::encode_data(predicate_bech32_address); + let predicate: Predicate = Predicate::load_from("test_artifacts/auth_predicate/out/debug/auth_predicate.bin").unwrap() + .with_provider(first_wallet.try_provider().unwrap().clone()) + .with_data(predicate_data); + + // Next, we lock some assets in this predicate using the first wallet: + // First wallet transfers amount to predicate. + first_wallet + .transfer(predicate.address(), 500, asset_id, TxPolicies::default()) + .await.unwrap(); + + // Check predicate balance. + let balance = predicate.get_asset_balance(&AssetId::default()).await.unwrap(); + assert_eq!(balance, 500); + + // Then we can transfer assets owned by the predicate via the Account trait: + let amount_to_unlock = 500; + + // Will transfer if the correct predicate address is passed as an argument to the predicate + predicate + .transfer( + second_wallet.address(), + amount_to_unlock, + asset_id, + TxPolicies::default(), + ) + .await.unwrap(); + + // Predicate balance is zero. + let balance = predicate.get_asset_balance(&AssetId::default()).await.unwrap(); + assert_eq!(balance, 0); + + // Second wallet balance is updated. + let balance = second_wallet.get_asset_balance(&AssetId::default()).await.unwrap(); + assert_eq!(balance, 1500); +} + +#[tokio::test] +#[should_panic] +async fn when_incorrect_predicate_address_passed() { + // Setup Wallets + let asset_id = AssetId::default(); + let wallets_config = WalletsConfig::new_multiple_assets( + 2, + vec![AssetConfig { + id: asset_id, + num_coins: 1, + coin_amount: 1_000, + }], + ); + let wallets = &launch_custom_provider_and_get_wallets(wallets_config, None, None).await.unwrap(); + let first_wallet = &wallets[0]; + let second_wallet = &wallets[1]; + + // Setup Predciate with incorrect address + let hex_predicate_address: &str = "0x36bf4bd40f2a3b3db595ef8fd8b21dbe9e6c0dd7b419b4413ff6b584ce7da5d7"; + let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string"); + let predicate_data = AuthPredicateEncoder::encode_data(Bech32Address::from(predicate_address)); + let predicate: Predicate = Predicate::load_from("test_artifacts/auth_predicate/out/debug/auth_predicate.bin").unwrap() + .with_provider(first_wallet.try_provider().unwrap().clone()) + .with_data(predicate_data); + + // Next, we lock some assets in this predicate using the first wallet: + // First wallet transfers amount to predicate. + first_wallet + .transfer(predicate.address(), 500, asset_id, TxPolicies::default()) + .await.unwrap(); + + // Check predicate balance. + let balance = predicate.get_asset_balance(&AssetId::default()).await.unwrap(); + assert_eq!(balance, 500); + + // Then we can transfer assets owned by the predicate via the Account trait: + let amount_to_unlock = 500; + + // Will should fail to transfer + predicate + .transfer( + second_wallet.address(), + amount_to_unlock, + asset_id, + TxPolicies::default(), + ) + .await.unwrap(); +} From 489fa445d0017672d9bb51a259c53822f214aa88 Mon Sep 17 00:00:00 2001 From: Marcos Henrich Date: Thu, 4 Jan 2024 05:31:09 +0000 Subject: [PATCH 7/9] Changes `ConcurrentSlab` to store values in map. (#5400) ## Description With these changes `ConcurrentSlab` now stores values in a map instead of a vector. This change is necessary to allow us to remove specific ids from the `ConcurrentSlab`. Before this, removing an index would change the vector and invalidate existing type and decls ids. This is required for `TypeEngine` and `DeclEngine` `clear_module` methods to work properly. This change implies a slowdown in the compile time of `cargo run --bin test --release` from ~9min to ~10min. I think the overhead is worth it because we now can remove values from ConcurrentSlab and optimize memory usage, which is mostly concentrated in the slabs. ## Checklist - [ ] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: Joshua Batty --- sway-core/src/concurrent_slab.rs | 32 ++++++++----- sway-core/src/decl_engine/engine.rs | 29 ++++++++---- .../ast_elements/type_parameter.rs | 3 +- sway-core/src/type_system/engine.rs | 46 ++++++++----------- sway-core/src/type_system/info.rs | 3 +- sway-core/src/type_system/unify/unifier.rs | 4 +- sway-error/src/error.rs | 9 +++- 7 files changed, 74 insertions(+), 52 deletions(-) diff --git a/sway-core/src/concurrent_slab.rs b/sway-core/src/concurrent_slab.rs index adc6caeb2c6..aabca4a0c8f 100644 --- a/sway-core/src/concurrent_slab.rs +++ b/sway-core/src/concurrent_slab.rs @@ -1,11 +1,15 @@ use std::{ + collections::HashMap, fmt, sync::{Arc, RwLock}, }; +use itertools::Itertools; + #[derive(Debug)] pub(crate) struct ConcurrentSlab { - inner: RwLock>>, + inner: RwLock>>, + last_id: Arc>, } impl Clone for ConcurrentSlab @@ -16,6 +20,7 @@ where let inner = self.inner.read().unwrap(); Self { inner: RwLock::new(inner.clone()), + last_id: self.last_id.clone(), } } } @@ -24,6 +29,7 @@ impl Default for ConcurrentSlab { fn default() -> Self { Self { inner: Default::default(), + last_id: Default::default(), } } } @@ -52,37 +58,39 @@ impl ConcurrentSlab where T: Clone, { - pub fn len(&self) -> usize { + pub fn values(&self) -> Vec> { let inner = self.inner.read().unwrap(); - inner.len() + inner.values().cloned().collect_vec() } pub fn insert(&self, value: T) -> usize { let mut inner = self.inner.write().unwrap(); - let ret = inner.len(); - inner.push(Arc::new(value)); - ret + let mut last_id = self.last_id.write().unwrap(); + *last_id += 1; + inner.insert(*last_id, Arc::new(value)); + *last_id } pub fn insert_arc(&self, value: Arc) -> usize { let mut inner = self.inner.write().unwrap(); - let ret = inner.len(); - inner.push(value); - ret + let mut last_id = self.last_id.write().unwrap(); + *last_id += 1; + inner.insert(*last_id, value); + *last_id } pub fn replace(&self, index: usize, new_value: T) -> Option { let mut inner = self.inner.write().unwrap(); - inner[index] = Arc::new(new_value); + inner.insert(index, Arc::new(new_value)); None } pub fn get(&self, index: usize) -> Arc { let inner = self.inner.read().unwrap(); - inner[index].clone() + inner[&index].clone() } - pub fn retain(&self, predicate: impl Fn(&Arc) -> bool) { + pub fn retain(&self, predicate: impl Fn(&usize, &mut Arc) -> bool) { let mut inner = self.inner.write().unwrap(); inner.retain(predicate); } diff --git a/sway-core/src/decl_engine/engine.rs b/sway-core/src/decl_engine/engine.rs index 4fb36bfd89e..fe789780fa8 100644 --- a/sway-core/src/decl_engine/engine.rs +++ b/sway-core/src/decl_engine/engine.rs @@ -168,8 +168,25 @@ macro_rules! decl_engine_clear_module { ($($slab:ident, $decl:ty);* $(;)?) => { impl DeclEngine { pub fn clear_module(&mut self, module_id: &ModuleId) { + self.parents.write().unwrap().retain(|key, _| { + match key { + AssociatedItemDeclId::TraitFn(decl_id) => { + self.get_trait_fn(decl_id).span().source_id().map_or(false, |src_id| &src_id.module_id() != module_id) + }, + AssociatedItemDeclId::Function(decl_id) => { + self.get_function(decl_id).span().source_id().map_or(false, |src_id| &src_id.module_id() != module_id) + }, + AssociatedItemDeclId::Type(decl_id) => { + self.get_type(decl_id).span().source_id().map_or(false, |src_id| &src_id.module_id() != module_id) + }, + AssociatedItemDeclId::Constant(decl_id) => { + self.get_constant(decl_id).span().source_id().map_or(false, |src_id| &src_id.module_id() != module_id) + }, + } + }); + $( - self.$slab.retain(|ty| match ty.span().source_id() { + self.$slab.retain(|_k, ty| match ty.span().source_id() { Some(source_id) => &source_id.module_id() != module_id, None => false, }); @@ -284,8 +301,7 @@ impl DeclEngine { /// to be used only for diagnostic purposes. pub fn get_traits_by_name(&self, trait_name: &Ident) -> Vec { let mut vec = vec![]; - for i in 0..self.trait_slab.len() { - let trait_decl = self.trait_slab.get(i); + for trait_decl in self.trait_slab.values() { if trait_decl.name == *trait_name { vec.push((*trait_decl).clone()) } @@ -407,11 +423,8 @@ impl DeclEngine { pub fn pretty_print(&self, engines: &Engines) -> String { let mut builder = String::new(); let mut list = vec![]; - for i in 0..self.function_slab.len() { - list.push(format!( - "{:?}", - engines.help_out(&*self.function_slab.get(i)) - )); + for func in self.function_slab.values() { + list.push(format!("{:?}", engines.help_out(&*func))); } let list = ListDisplay { list }; write!(builder, "DeclEngine {{\n{list}\n}}").unwrap(); 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 a7b619d13a5..32594e835de 100644 --- a/sway-core/src/type_system/ast_elements/type_parameter.rs +++ b/sway-core/src/type_system/ast_elements/type_parameter.rs @@ -336,7 +336,8 @@ impl TypeParameter { type_info: TypeInfo::UnknownGeneric { name: type_parameter.name_ident.clone(), trait_constraints: VecSet(trait_constraints_with_supertraits.clone()), - }, + } + .into(), source_id: type_parameter.name_ident.span().source_id().cloned(), }, ); diff --git a/sway-core/src/type_system/engine.rs b/sway-core/src/type_system/engine.rs index 2606a9c2010..6e3c86bec1b 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -6,10 +6,7 @@ use crate::{ }; use core::fmt::Write; use hashbrown::{hash_map::RawEntryMut, HashMap}; -use std::{ - ops::Deref, - sync::{Arc, RwLock}, -}; +use std::sync::{Arc, RwLock}; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, @@ -21,8 +18,7 @@ use super::unify::unifier::UnifyKind; #[derive(Debug, Default)] pub struct TypeEngine { - slab: ConcurrentSlab, - slab_source_ids: ConcurrentSlab>, + slab: ConcurrentSlab, id_map: RwLock>, } @@ -39,7 +35,7 @@ impl TypeEngine { .map(Clone::clone) .or_else(|| info_to_source_id(&ty)); let tsi = TypeSourceInfo { - type_info: ty.clone(), + type_info: ty.clone().into(), source_id, }; let mut id_map = self.id_map.write().unwrap(); @@ -53,16 +49,10 @@ impl TypeEngine { match raw_entry { RawEntryMut::Occupied(o) => return *o.get(), RawEntryMut::Vacant(_) if ty.can_change(engines.de()) => { - let t1 = self.slab.insert(ty); - let t2 = self.slab_source_ids.insert(source_id); - assert!(t1 == t2); - TypeId::new(t1) + TypeId::new(self.slab.insert(tsi)) } RawEntryMut::Vacant(v) => { - let t1 = self.slab.insert(ty); - let t2 = self.slab_source_ids.insert(source_id); - assert!(t1 == t2); - let type_id = TypeId::new(t1); + let type_id = TypeId::new(self.slab.insert(tsi.clone())); v.insert_with_hasher(ty_hash, tsi, type_id, make_hasher(&hash_builder, engines)); type_id } @@ -71,22 +61,26 @@ impl TypeEngine { /// Removes all data associated with `module_id` from the type engine. pub fn clear_module(&mut self, module_id: &ModuleId) { - self.slab_source_ids - .retain(|source_id| match source_id.deref() { + self.slab.retain(|_, tsi| match tsi.source_id { + Some(source_id) => &source_id.module_id() != module_id, + None => false, + }); + self.id_map + .write() + .unwrap() + .retain(|tsi, _| match tsi.source_id { Some(source_id) => &source_id.module_id() != module_id, None => false, }); } pub fn replace(&self, id: TypeId, new_value: TypeSourceInfo) { - self.slab.replace(id.index(), new_value.type_info); - self.slab_source_ids - .replace(id.index(), new_value.source_id); + self.slab.replace(id.index(), new_value); } /// Performs a lookup of `id` into the [TypeEngine]. pub fn get(&self, id: TypeId) -> Arc { - self.slab.get(id.index()) + self.slab.get(id.index()).type_info.clone() } /// Performs a lookup of `id` into the [TypeEngine] recursing when finding a @@ -94,10 +88,10 @@ impl TypeEngine { pub fn get_unaliased(&self, id: TypeId) -> Arc { // A slight infinite loop concern if we somehow have self-referential aliases, but that // shouldn't be possible. - let type_info = self.slab.get(id.index()); - match &*type_info { + let tsi = self.slab.get(id.index()); + match &*tsi.type_info { TypeInfo::Alias { ty, .. } => self.get_unaliased(ty.type_id), - _ => type_info, + _ => tsi.type_info.clone(), } } @@ -364,8 +358,8 @@ impl TypeEngine { pub fn pretty_print(&self, _decl_engine: &DeclEngine, engines: &Engines) -> String { let mut builder = String::new(); let mut list = vec![]; - for i in 0..self.slab.len() { - list.push(format!("{:?}", engines.help_out(&*self.slab.get(i)))); + for tsi in self.slab.values() { + list.push(format!("{:?}", engines.help_out(&*tsi.type_info))); } let list = ListDisplay { list }; write!(builder, "TypeEngine {{\n{list}\n}}").unwrap(); diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index 94912dd5aed..7d7c87e3d72 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -15,6 +15,7 @@ use std::{ cmp::Ordering, fmt, hash::{Hash, Hasher}, + sync::Arc, }; #[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)] @@ -70,7 +71,7 @@ impl PartialEqWithEngines for VecSet { /// Encapsulates type information and its optional source identifier. #[derive(Debug, Default, Clone)] pub struct TypeSourceInfo { - pub(crate) type_info: TypeInfo, + pub(crate) type_info: Arc, /// The source id that created this type. pub(crate) source_id: Option, } diff --git a/sway-core/src/type_system/unify/unifier.rs b/sway-core/src/type_system/unify/unifier.rs index fcdb4b2cc73..258c5201cdc 100644 --- a/sway-core/src/type_system/unify/unifier.rs +++ b/sway-core/src/type_system/unify/unifier.rs @@ -61,7 +61,7 @@ impl<'a> Unifier<'a> { type_engine.replace( received, TypeSourceInfo { - type_info: expected_type_info.clone(), + type_info: expected_type_info.clone().into(), source_id, }, ); @@ -79,7 +79,7 @@ impl<'a> Unifier<'a> { type_engine.replace( expected, TypeSourceInfo { - type_info: received_type_info.clone(), + type_info: received_type_info.clone().into(), source_id, }, ); diff --git a/sway-error/src/error.rs b/sway-error/src/error.rs index c0baf598058..1e8f4a56497 100644 --- a/sway-error/src/error.rs +++ b/sway-error/src/error.rs @@ -1138,7 +1138,12 @@ impl ToDiagnostic for CompileError { format!("Consider removing the variable \"{variable}\" altogether, or adding it to all alternatives."), ], }, - TraitNotImportedAtFunctionApplication { trait_name, function_name, function_call_site_span, trait_constraint_span, trait_candidates }=> Diagnostic { + TraitNotImportedAtFunctionApplication { trait_name, function_name, function_call_site_span, trait_constraint_span, trait_candidates }=> { + // Make candidates order deterministic + let mut trait_candidates = trait_candidates.clone(); + trait_candidates.sort(); + let trait_candidates = &trait_candidates; + Diagnostic { reason: Some(Reason::new(code(1), "Trait is not imported".to_string())), issue: Issue::error( source_engine, @@ -1221,7 +1226,7 @@ impl ToDiagnostic for CompileError { help }, - }, + }}, _ => Diagnostic { // TODO: Temporary we use self here to achieve backward compatibility. // In general, self must not be used and will not be used once we From bae4be893fef73f704ec9b207464f9233d3dd4c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Ron=C4=8Devi=C4=87?= Date: Thu, 4 Jan 2024 23:08:36 +0100 Subject: [PATCH 8/9] Add references to Sway (#5406) ## Description This PR brings [references](https://github.com/FuelLabs/sway-rfcs/blob/ironcev/amend-references/files/0010-references.sw) to the language. The overall effort is tracked in #5063. In the below description, when talking about references we mean `&T` references - references to immutable values. `&mut T` will be implemented in upcoming PRs. The PR implements the following features: - References exist in the type system and can be declared, aliased, dereferenced using `*` operator, etc. - Reference expressions (referencing) are fully supported on all expressions including the nonsensical one like e.g. `&return;` - Semantic analysis and checks are implemented for the current functionality. - References can be embedded in aggregates. - References can reference parts of aggreagates. - References can be passed to and returned from ASM blocks. - References can be passed to and returned from functions. - References can be mutable: `let mut r_x = &x` - Impls can be implemented for non-generic reference types. - Traits can be implemented for non-generic reference types. - References work with generics, means `&T` works as expected. - References can reference references. - References can be dereferenced using the `*` operator. - Dereference expressions (dereferencing) are fully supported on all expressions including the nonsensical one like e.g. `*&return;` Known limitations: - When declaring references on references, currently a space (' ') is mandatory between two ampersands. E.g., `&&a` emits error and must be written as `& &a`. Extending parser to support, e.g., arbitrary `&&...&&a` will be done in upcoming PRs. - Referencing function parameters for copy types works but not with 100% proper semantics (creates a copy of the parameter). On the IR level, references are pointers stored as `u64` and do not exist as a separate concept. They play well with all the existing IR optimizations. Since `core::ops::Eq` and `__addr_of()` are still not implemented for references, checking for equality in tests is done by converting references to `raw_ptr`s and checking raw pointers. This is essentially fine and will one day be turned into converting references to typed pointers which are tests we will anyhow want to have. Next steps are listed in #5063. The documentation will be done in a separate PR and provided separately once feature is considered ready for public usage. There are several todos in code marked as `TODO-IG`. They will be resolved in upcoming PRs. # Demo For extensive demos of implemented features, see the tests in this PR. An example of a semantic check: ![Expression cannot be dereferenced](https://github.com/FuelLabs/sway/assets/4142833/0d1a3576-3725-4a70-abf2-e5e11625f429) ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers. --- sway-ast/src/expr/mod.rs | 11 +- sway-ast/src/keywords.rs | 7 +- sway-ast/src/pattern.rs | 2 +- sway-ast/src/ty/mod.rs | 8 + sway-core/src/abi_generation/evm_abi.rs | 3 + sway-core/src/abi_generation/fuel_abi.rs | 3 + .../src/asm_generation/fuel/data_section.rs | 3 + .../miden_vm/miden_vm_asm_builder.rs | 1 + .../dead_code_analysis.rs | 11 + sway-core/src/ir_generation/const_eval.rs | 6 + sway-core/src/ir_generation/convert.rs | 7 +- sway-core/src/ir_generation/function.rs | 136 +++++- .../src/language/parsed/expression/mod.rs | 2 + .../src/language/ty/expression/expression.rs | 4 +- .../ty/expression/expression_variant.rs | 28 +- sway-core/src/lib.rs | 2 +- .../ast_node/expression/typed_expression.rs | 72 +++ .../semantic_analysis/cei_pattern_analysis.rs | 8 +- .../src/semantic_analysis/coins_analysis.rs | 4 +- .../semantic_analysis/node_dependencies.rs | 4 + .../semantic_analysis/type_check_context.rs | 20 + .../to_parsed_lang/convert_parse_tree.rs | 29 +- sway-core/src/type_system/engine.rs | 7 +- sway-core/src/type_system/id.rs | 7 + sway-core/src/type_system/info.rs | 107 +++-- .../src/type_system/substitute/subst_map.rs | 21 +- sway-core/src/type_system/unify/unifier.rs | 32 +- .../src/type_system/unify/unify_check.rs | 7 +- sway-error/src/convert_parse_tree_error.rs | 6 - sway-error/src/error.rs | 184 ++++---- sway-ir/src/constant.rs | 1 + sway-ir/src/error.rs | 2 +- sway-ir/src/irtype.rs | 10 +- sway-ir/src/optimize/target_fuel.rs | 2 +- sway-ir/src/printer.rs | 1 + sway-ir/src/value.rs | 4 +- sway-ir/src/verify.rs | 2 +- sway-lib-core/src/raw_ptr.sw | 4 +- sway-lsp/src/traverse/lexed_tree.rs | 6 +- sway-lsp/src/traverse/parsed_tree.rs | 3 + sway-lsp/src/traverse/typed_tree.rs | 3 + sway-parse/src/expr/mod.rs | 11 +- sway-parse/src/item/item_impl.rs | 20 + sway-parse/src/keywords.rs | 2 - sway-parse/src/ty/mod.rs | 19 +- swayfmt/src/utils/language/expr/mod.rs | 22 +- swayfmt/src/utils/language/ty.rs | 28 +- .../src/main.sw | 8 +- .../asm_read_from_uninitialized_reg/test.toml | 8 +- .../ref_and_deref_expressions/src/main.sw | 2 +- .../ref_and_deref_expressions/test.toml | 2 +- .../Forc.lock | 13 + .../Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../src/main.sw | 114 +++++ .../test.toml | 4 + .../dereferencing_operator_star/Forc.lock | 13 + .../dereferencing_operator_star/Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../dereferencing_operator_star/src/impls.sw | 258 ++++++++++ .../dereferencing_operator_star/src/main.sw | 443 ++++++++++++++++++ .../dereferencing_operator_star/test.toml | 4 + .../references/impl_reference_types/Forc.lock | 13 + .../references/impl_reference_types/Forc.toml | 8 + .../impl_reference_types/json_abi_oracle.json | 25 + .../impl_reference_types/src/main.sw | 154 ++++++ .../references/impl_reference_types/test.toml | 4 + .../mutability_of_references/Forc.lock | 13 + .../mutability_of_references/Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../mutability_of_references/src/main.sw | 35 ++ .../mutability_of_references/test.toml | 4 + .../Forc.lock | 13 + .../Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../src/main.sw | 205 ++++++++ .../test.toml | 4 + .../references_and_generics/Forc.lock | 13 + .../references_and_generics/Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../references_and_generics/src/main.sw | 69 +++ .../references_and_generics/test.toml | 4 + .../references_and_type_aliases/Forc.lock | 13 + .../references_and_type_aliases/Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../references_and_type_aliases/src/main.sw | 35 ++ .../references_and_type_aliases/test.toml | 4 + .../references_in_aggregates/Forc.lock | 13 + .../references_in_aggregates/Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../references_in_aggregates/src/main.sw | 240 ++++++++++ .../references_in_aggregates/test.toml | 4 + .../references_in_asm_blocks/Forc.lock | 13 + .../references_in_asm_blocks/Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../references_in_asm_blocks/src/main.sw | 129 +++++ .../references_in_asm_blocks/test.toml | 4 + .../Forc.lock | 13 + .../Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../src/main.sw | 114 +++++ .../test.toml | 4 + .../referencing_expressions/Forc.lock | 13 + .../referencing_expressions/Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../referencing_expressions/src/main.sw | 80 ++++ .../referencing_expressions/test.toml | 4 + .../referencing_function_parameters/Forc.lock | 13 + .../referencing_function_parameters/Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../src/main.sw | 230 +++++++++ .../referencing_function_parameters/test.toml | 4 + .../Forc.lock | 13 + .../Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../src/impls.sw | 229 +++++++++ .../src/main.sw | 261 +++++++++++ .../test.toml | 4 + .../referencing_parts_of_aggregates/Forc.lock | 13 + .../referencing_parts_of_aggregates/Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../src/main.sw | 258 ++++++++++ .../referencing_parts_of_aggregates/test.toml | 4 + .../referencing_references/Forc.lock | 13 + .../referencing_references/Forc.toml | 8 + .../json_abi_oracle.json | 25 + .../referencing_references/src/main.sw | 84 ++++ .../referencing_references/test.toml | 4 + 128 files changed, 4360 insertions(+), 230 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/src/impls.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/src/impls.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/test.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/test.toml diff --git a/sway-ast/src/expr/mod.rs b/sway-ast/src/expr/mod.rs index 27d37382e72..118da3d2909 100644 --- a/sway-ast/src/expr/mod.rs +++ b/sway-ast/src/expr/mod.rs @@ -68,11 +68,11 @@ pub enum Expr { field_span: Span, }, Ref { - ref_token: RefToken, + ampersand_token: AmpersandToken, expr: Box, }, Deref { - deref_token: DerefToken, + star_token: StarToken, expr: Box, }, Not { @@ -227,8 +227,11 @@ impl Spanned for Expr { Expr::TupleFieldProjection { target, field_span, .. } => Span::join(target.span(), field_span.clone()), - Expr::Ref { ref_token, expr } => Span::join(ref_token.span(), expr.span()), - Expr::Deref { deref_token, expr } => Span::join(deref_token.span(), expr.span()), + Expr::Ref { + ampersand_token, + expr, + } => Span::join(ampersand_token.span(), expr.span()), + Expr::Deref { star_token, expr } => Span::join(star_token.span(), expr.span()), Expr::Not { bang_token, expr } => Span::join(bang_token.span(), expr.span()), Expr::Pow { lhs, rhs, .. } => Span::join(lhs.span(), rhs.span()), Expr::Mul { lhs, rhs, .. } => Span::join(lhs.span(), rhs.span()), diff --git a/sway-ast/src/keywords.rs b/sway-ast/src/keywords.rs index 949b0ee2c14..4ab0554bbb3 100644 --- a/sway-ast/src/keywords.rs +++ b/sway-ast/src/keywords.rs @@ -75,7 +75,6 @@ define_keyword!(LetToken, "let"); define_keyword!(WhileToken, "while"); define_keyword!(WhereToken, "where"); define_keyword!(RefToken, "ref"); -define_keyword!(DerefToken, "deref"); define_keyword!(TrueToken, "true"); define_keyword!(FalseToken, "false"); define_keyword!(BreakToken, "break"); @@ -85,12 +84,12 @@ define_keyword!(TypeToken, "type"); define_keyword!(PtrToken, "__ptr"); define_keyword!(SliceToken, "__slice"); -/// The type is a keyword. +/// The type is a token. pub trait Token: Spanned + Sized { - /// Creates the keyword from the given `span`. + /// Creates the token from the given `span`. fn new(span: Span) -> Self; - /// Returns an identifier for this keyword. + /// Returns an identifier for this token. fn ident(&self) -> Ident; /// The sequence of punctuations that make up the token. diff --git a/sway-ast/src/pattern.rs b/sway-ast/src/pattern.rs index 1b095aadea1..db20a445d85 100644 --- a/sway-ast/src/pattern.rs +++ b/sway-ast/src/pattern.rs @@ -15,7 +15,7 @@ pub enum Pattern { /// A pattern made of a single ident, which could either be a variable or an enum variant AmbiguousSingleIdent(Ident), Var { - reference: Option, + reference: Option, // TODO-IG: Remove this and replace with proper support for references in patterns. mutable: Option, name: Ident, }, diff --git a/sway-ast/src/ty/mod.rs b/sway-ast/src/ty/mod.rs index 939dab414e1..69429504d6e 100644 --- a/sway-ast/src/ty/mod.rs +++ b/sway-ast/src/ty/mod.rs @@ -22,6 +22,10 @@ pub enum Ty { slice_token: SliceToken, ty: SquareBrackets>, }, + Ref { + ampersand_token: AmpersandToken, + ty: Box, + }, } impl Spanned for Ty { @@ -35,6 +39,10 @@ impl Spanned for Ty { Ty::Infer { underscore_token } => underscore_token.span(), Ty::Ptr { ptr_token, ty } => Span::join(ptr_token.span(), ty.span()), Ty::Slice { slice_token, ty } => Span::join(slice_token.span(), ty.span()), + Ty::Ref { + ampersand_token, + ty, + } => Span::join(ampersand_token.span(), ty.span()), } } } diff --git a/sway-core/src/abi_generation/evm_abi.rs b/sway-core/src/abi_generation/evm_abi.rs index f81f91a895a..5a2a047e001 100644 --- a/sway-core/src/abi_generation/evm_abi.rs +++ b/sway-core/src/abi_generation/evm_abi.rs @@ -144,6 +144,9 @@ pub fn abi_str(type_info: &TypeInfo, type_engine: &TypeEngine, decl_engine: &Dec name, trait_type_id: _, } => format!("trait type {}", name), + Ref(ty) => { + format!("__ref {}", abi_str_type_arg(ty, type_engine, decl_engine)) // TODO-IG: No references in ABIs according to the RFC. Or we want to have them? + } } } diff --git a/sway-core/src/abi_generation/fuel_abi.rs b/sway-core/src/abi_generation/fuel_abi.rs index 0f732a545b3..edd970761ed 100644 --- a/sway-core/src/abi_generation/fuel_abi.rs +++ b/sway-core/src/abi_generation/fuel_abi.rs @@ -850,6 +850,9 @@ impl TypeInfo { name, trait_type_id: _, } => format!("trait type {}", name), + Ref(ty) => { + format!("__ref {}", ty.abi_str(ctx, type_engine, decl_engine)) // TODO-IG: No references in ABIs according to the RFC. Or we want to have them? + } } } } diff --git a/sway-core/src/asm_generation/fuel/data_section.rs b/sway-core/src/asm_generation/fuel/data_section.rs index f2f39617d90..5eb9999692a 100644 --- a/sway-core/src/asm_generation/fuel/data_section.rs +++ b/sway-core/src/asm_generation/fuel/data_section.rs @@ -124,6 +124,9 @@ impl Entry { name, padding, ), + ConstantValue::Reference(_) => { + todo!("Constant references are currently not supported.") + } // TODO-IG: Implement. } } diff --git a/sway-core/src/asm_generation/miden_vm/miden_vm_asm_builder.rs b/sway-core/src/asm_generation/miden_vm/miden_vm_asm_builder.rs index 0f2ca13d8b7..f3511ae7cef 100644 --- a/sway-core/src/asm_generation/miden_vm/miden_vm_asm_builder.rs +++ b/sway-core/src/asm_generation/miden_vm/miden_vm_asm_builder.rs @@ -658,6 +658,7 @@ impl<'ir, 'eng> MidenVMAsmBuilder<'ir, 'eng> { String(_) => todo!(), Array(_) => todo!(), Struct(_) => todo!(), + Reference(_) => todo!(), } } } 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 9d03d50d092..f93ad83a4a4 100644 --- a/sway-core/src/control_flow_analysis/dead_code_analysis.rs +++ b/sway-core/src/control_flow_analysis/dead_code_analysis.rs @@ -1858,6 +1858,17 @@ fn connect_expression<'eng: 'cfg, 'cfg>( } Ok(vec![]) } + Ref(exp) | Deref(exp) => connect_expression( + engines, + &exp.expression, + graph, + leaves, + exit_node, + "", + tree_type, + exp.span.clone(), + options, + ), } } diff --git a/sway-core/src/ir_generation/const_eval.rs b/sway-core/src/ir_generation/const_eval.rs index e3ab77d5e92..1a64ce33ecc 100644 --- a/sway-core/src/ir_generation/const_eval.rs +++ b/sway-core/src/ir_generation/const_eval.rs @@ -622,6 +622,12 @@ fn const_eval_typed_expr( } } } + ty::TyExpressionVariant::Ref(_) | ty::TyExpressionVariant::Deref(_) => { + return Err(ConstEvalError::CompileError(CompileError::Unimplemented( + "Constant references are currently not supported.", + expr.span.clone(), + ))); + } ty::TyExpressionVariant::Reassignment(_) | ty::TyExpressionVariant::FunctionParameter | ty::TyExpressionVariant::AsmExpression { .. } diff --git a/sway-core/src/ir_generation/convert.rs b/sway-core/src/ir_generation/convert.rs index bda60d85102..a534915cc25 100644 --- a/sway-core/src/ir_generation/convert.rs +++ b/sway-core/src/ir_generation/convert.rs @@ -14,9 +14,9 @@ use sway_types::{integer_bits::IntegerBits, span::Span}; pub(super) fn convert_literal_to_value(context: &mut Context, ast_literal: &Literal) -> Value { match ast_literal { // In Sway for now we don't have `as` casting and for integers which may be implicitly cast - // between widths we just emit a warning, and essentially ignore it. We also assume a - // 'Numeric' integer of undetermined width is 'u64`. The IR would like to be type - // consistent and doesn't tolerate mising integers of different width, so for now, until we + // between widths we just emit a warning, and essentially ignore it. We also assume a + // 'Numeric' integer of undetermined width is 'u64`. The IR would like to be type + // consistent and doesn't tolerate missing integers of different width, so for now, until we // do introduce explicit `as` casting, all integers are `u64` as far as the IR is // concerned. // @@ -158,6 +158,7 @@ fn convert_resolved_type( TypeInfo::Alias { ty, .. } => { convert_resolved_typeid(type_engine, decl_engine, context, &ty.type_id, span)? } + TypeInfo::Ref(_) => Type::get_uint64(context), // Unsupported types which shouldn't exist in the AST after type checking and // monomorphisation. diff --git a/sway-core/src/ir_generation/function.rs b/sway-core/src/ir_generation/function.rs index 761ddcd5429..5b41feafef1 100644 --- a/sway-core/src/ir_generation/function.rs +++ b/sway-core/src/ir_generation/function.rs @@ -36,25 +36,25 @@ use std::collections::HashMap; /// /// This is mostly recursively compiling expressions, as Sway is fairly heavily expression based. /// -/// The rule here is to use compile_expression_to_value() when a value is desired, as opposed to a +/// The rule here is to use `compile_expression_to_value()` when a value is desired, as opposed to a /// pointer. This is most of the time, as we try to be target agnostic and not make assumptions /// about which values must be used by reference. /// -/// compile_expression_to_value() will force the result to be a value, by using a temporary if +/// `compile_expression_to_value()` will force the result to be a value, by using a temporary if /// necessary. /// -/// compile_expression_to_ptr() will compile the expression and force it to be a pointer, also by -/// using a temporary if necessary. This can be slightly dangerous, if the reference is supposed +/// `compile_expression_to_ptr()` will compile the expression and force it to be a pointer, also by +/// using a temporary if necessary. This can be slightly dangerous, if the reference is supposed /// to be to a particular value but is accidentally made to a temporary value then mutations or /// other side-effects might not be applied in the correct context. /// -/// compile_expression() will compile the expression without forcing anything. If the expression +/// `compile_expression()` will compile the expression without forcing anything. If the expression /// has a reference type, like getting a struct or an explicit ref arg, it will return a pointer /// value, but otherwise will return a value. /// -/// So in general the methods in FnCompiler will return a pointer if they can and will get it be -/// forced into a value if that is desired. All the temporary values are manipulated with simple -/// loads and stores, rather than anything more complicated like mem_copys. +/// So in general the methods in [FnCompiler] will return a pointer if they can and will get it, be +/// forced, into a value if that is desired. All the temporary values are manipulated with simple +/// loads and stores, rather than anything more complicated like `mem_copy`s. pub(crate) struct FnCompiler<'eng> { engines: &'eng Engines, @@ -558,7 +558,13 @@ impl<'eng> FnCompiler<'eng> { self.compile_reassignment(context, md_mgr, reassignment, span_md_idx) } ty::TyExpressionVariant::Return(exp) => { - self.compile_return_statement(context, md_mgr, exp) + self.compile_return(context, md_mgr, exp, span_md_idx) + } + ty::TyExpressionVariant::Ref(exp) => { + self.compile_ref(context, md_mgr, exp, span_md_idx) + } + ty::TyExpressionVariant::Deref(exp) => { + self.compile_deref(context, md_mgr, exp, span_md_idx) } } } @@ -1103,11 +1109,12 @@ impl<'eng> FnCompiler<'eng> { } } - fn compile_return_statement( + fn compile_return( &mut self, context: &mut Context, md_mgr: &mut MetadataManager, ast_expr: &ty::TyExpression, + span_md_idx: Option, ) -> Result { // Nothing to do if the current block already has a terminator if self.current_block.is_terminated(context) { @@ -1119,7 +1126,6 @@ impl<'eng> FnCompiler<'eng> { return Ok(ret_value); } - let span_md_idx = md_mgr.span_to_md(context, &ast_expr.span); ret_value .get_type(context) .map(|ret_ty| { @@ -1130,12 +1136,99 @@ impl<'eng> FnCompiler<'eng> { }) .ok_or_else(|| { CompileError::Internal( - "Unable to determine type for return statement expression.", + "Unable to determine type for return expression.", ast_expr.span.clone(), ) }) } + fn compile_ref( + &mut self, + context: &mut Context, + md_mgr: &mut MetadataManager, + ast_expr: &ty::TyExpression, + span_md_idx: Option, + ) -> Result { + let value = self.compile_expression_to_ptr(context, md_mgr, ast_expr)?; + + if value.is_diverging(context) { + return Ok(value); + } + + // TODO-IG: Do we need to convert to `u64` here? Can we use `Ptr` directly? Investigate. + let int_ty = Type::get_uint64(context); + Ok(self + .current_block + .append(context) + .ptr_to_int(value, int_ty) + .add_metadatum(context, span_md_idx)) + } + + fn compile_deref( + &mut self, + context: &mut Context, + md_mgr: &mut MetadataManager, + ast_expr: &ty::TyExpression, + span_md_idx: Option, + ) -> Result { + let ref_value = self.compile_expression(context, md_mgr, ast_expr)?; + + if ref_value.is_diverging(context) { + return Ok(ref_value); + } + + let ptr_as_int = if ref_value + .get_type(context) + .map_or(false, |ref_value_type| ref_value_type.is_ptr(context)) + { + // We are dereferencing a reference variable and we got a pointer to it. + // To get the address the reference is pointing to we need to load the value. + self.current_block.append(context).load(ref_value) + } else { + // The value itself is the address. + ref_value + }; + + let reference_type = self.engines.te().get_unaliased(ast_expr.return_type); + + let referenced_ast_type = match *reference_type { + TypeInfo::Ref(ref referenced_type) => Ok(referenced_type.type_id), + _ => Err(CompileError::Internal( + "Cannot dereference a non-reference expression.", + ast_expr.span.clone(), + )), + }?; + + let referenced_ir_type = convert_resolved_typeid( + self.engines.te(), + self.engines.de(), + context, + &referenced_ast_type, + &ast_expr.span.clone(), + )?; + + let ptr_type = Type::new_ptr(context, referenced_ir_type); + let ptr = self + .current_block + .append(context) + .int_to_ptr(ptr_as_int, ptr_type) + .add_metadatum(context, span_md_idx); + + let referenced_type = self.engines.te().get_unaliased(referenced_ast_type); + + let result = if referenced_type.is_copy_type() || referenced_type.is_reference_type() { + // For non aggregates, we need to return the value. + // This means, loading the value the `ptr` is pointing to. + self.current_block.append(context).load(ptr) + } else { + // For aggregates, we access them via pointer, so we just + // need to return the `ptr`. + ptr + }; + + Ok(result) + } + fn compile_lazy_op( &mut self, context: &mut Context, @@ -1905,6 +1998,7 @@ impl<'eng> FnCompiler<'eng> { if init_val.is_diverging(context) || body_deterministically_aborts { return Ok(Some(init_val)); } + let mutable = matches!(mutability, ty::VariableMutability::Mutable); let local_name = self.lexical_map.insert(name.as_str().to_owned()); let local_var = self @@ -2695,18 +2789,24 @@ impl<'eng> FnCompiler<'eng> { .map(|init_expr| { self.compile_expression(context, md_mgr, init_expr) .map(|init_val| { + let init_type = + self.engines.te().get_unaliased(init_expr.return_type); + if init_val .get_type(context) .map_or(false, |ty| ty.is_ptr(context)) - && self - .engines - .te() - .get_unaliased(init_expr.return_type) - .is_copy_type() + && (init_type.is_copy_type() + || init_type.is_reference_type()) { - // It's a pointer to a copy type. We need to derefence it. + // It's a pointer to a copy type, or a reference behind a pointer. We need to dereference it. + // We can get a reference behind a pointer if a reference variable is passed to the ASM block. + // By "reference" we mean th `u64` value that represents the memory address of the referenced + // value. self.current_block.append(context).load(init_val) } else { + // If we have a direct value (not behind a pointer), we just passe it as the initial value. + // Note that if the `init_val` is a reference (`u64` representing the memory address) it + // behaves the same as any other value, we just passe it as the initial value to the register. init_val } }) diff --git a/sway-core/src/language/parsed/expression/mod.rs b/sway-core/src/language/parsed/expression/mod.rs index f3b7c6686b9..281b3ddf99b 100644 --- a/sway-core/src/language/parsed/expression/mod.rs +++ b/sway-core/src/language/parsed/expression/mod.rs @@ -308,6 +308,8 @@ pub enum ExpressionKind { Continue, Reassignment(ReassignmentExpression), Return(Box), + Ref(Box), + Deref(Box), } #[derive(Debug, Clone)] diff --git a/sway-core/src/language/ty/expression/expression.rs b/sway-core/src/language/ty/expression/expression.rs index ec366939dad..c82dc35f75a 100644 --- a/sway-core/src/language/ty/expression/expression.rs +++ b/sway-core/src/language/ty/expression/expression.rs @@ -292,6 +292,7 @@ impl CollectTypesMetadata for TyExpression { } } Return(exp) => res.append(&mut exp.collect_types_metadata(handler, ctx)?), + Ref(exp) | Deref(exp) => res.append(&mut exp.collect_types_metadata(handler, ctx)?), // storage access can never be generic // variable expressions don't ever have return types themselves, they're stored in // `TyExpression::return_type`. Variable expressions are just names of variables. @@ -404,7 +405,8 @@ impl DeterministicallyAborts for TyExpression { // Also, is it necessary to check the expression to see if avoids the return? eg. // someone could write `return break;` in a loop, which would mean the return never // gets executed. - Return(..) => true, + Return(_) => true, + Ref(exp) | Deref(exp) => exp.deterministically_aborts(decl_engine, check_call_body), } } } diff --git a/sway-core/src/language/ty/expression/expression_variant.rs b/sway-core/src/language/ty/expression/expression_variant.rs index 4ee0389c7d9..18d0f550489 100644 --- a/sway-core/src/language/ty/expression/expression_variant.rs +++ b/sway-core/src/language/ty/expression/expression_variant.rs @@ -143,6 +143,8 @@ pub enum TyExpressionVariant { Continue, Reassignment(Box), Return(Box), + Ref(Box), + Deref(Box), } impl EqWithEngines for TyExpressionVariant {} @@ -601,6 +603,9 @@ impl HashWithEngines for TyExpressionVariant { Self::Return(exp) => { exp.hash(state, engines); } + Self::Ref(exp) | Self::Deref(exp) => { + exp.hash(state, engines); + } } } } @@ -745,6 +750,7 @@ impl SubstTypes for TyExpressionVariant { Continue => (), Reassignment(reassignment) => reassignment.subst(type_mapping, engines), Return(stmt) => stmt.subst(type_mapping, engines), + Ref(exp) | Deref(exp) => exp.subst(type_mapping, engines), } } } @@ -892,6 +898,7 @@ impl ReplaceDecls for TyExpressionVariant { reassignment.replace_decls(decl_mapping, handler, ctx)? } Return(stmt) => stmt.replace_decls(decl_mapping, handler, ctx)?, + Ref(exp) | Deref(exp) => exp.replace_decls(decl_mapping, handler, ctx)?, } Ok(()) @@ -1006,6 +1013,9 @@ impl TypeCheckAnalysis for TyExpressionVariant { TyExpressionVariant::Return(node) => { node.type_check_analyze(handler, ctx)?; } + TyExpressionVariant::Ref(exp) | TyExpressionVariant::Deref(exp) => { + exp.type_check_analyze(handler, ctx)?; + } } Ok(()) } @@ -1141,6 +1151,9 @@ impl TypeCheckFinalization for TyExpressionVariant { TyExpressionVariant::Return(node) => { node.type_check_finalize(handler, ctx)?; } + TyExpressionVariant::Ref(exp) | TyExpressionVariant::Deref(exp) => { + exp.type_check_finalize(handler, ctx)?; + } } Ok(()) }) @@ -1243,6 +1256,7 @@ impl UpdateConstantExpression for TyExpressionVariant { reassignment.update_constant_expression(engines, implementing_type) } Return(stmt) => stmt.update_constant_expression(engines, implementing_type), + Ref(exp) | Deref(exp) => exp.update_constant_expression(engines, implementing_type), } } } @@ -1405,6 +1419,12 @@ impl DebugWithEngines for TyExpressionVariant { TyExpressionVariant::Return(exp) => { format!("return {:?}", engines.help_out(&**exp)) } + TyExpressionVariant::Ref(exp) => { + format!("&({:?})", engines.help_out(&**exp)) + } + TyExpressionVariant::Deref(exp) => { + format!("*({:?})", engines.help_out(&**exp)) + } }; write!(f, "{s}") } @@ -1419,8 +1439,8 @@ impl TyExpressionVariant { } } - /// recurse into `self` and get any return statements -- used to validate that all returns - /// do indeed return the correct type + /// Recurse into `self` and get any return statements -- used to validate that all returns + /// do indeed return the correct type. /// This does _not_ extract implicit return statements as those are not control flow! This is /// _only_ for explicit returns. pub(crate) fn gather_return_statements(&self) -> Vec<&TyExpression> { @@ -1515,10 +1535,12 @@ impl TyExpressionVariant { .collect(), TyExpressionVariant::EnumTag { exp } => exp.gather_return_statements(), TyExpressionVariant::UnsafeDowncast { exp, .. } => exp.gather_return_statements(), - TyExpressionVariant::Return(exp) => { vec![exp] } + TyExpressionVariant::Ref(exp) | TyExpressionVariant::Deref(exp) => { + exp.gather_return_statements() + } // if it is impossible for an expression to contain a return _statement_ (not an // implicit return!), put it in the pattern below. TyExpressionVariant::Literal(_) diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index d390800cd56..8c1e6033562 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -726,7 +726,7 @@ pub(crate) fn compile_ast_to_ir_to_asm( program: &ty::TyProgram, build_config: &BuildConfig, ) -> Result { - // the IR pipeline relies on type information being fully resolved. + // The IR pipeline relies on type information being fully resolved. // If type information is found to still be generic or unresolved inside of // IR, this is considered an internal compiler error. To resolve this situation, // we need to explicitly ensure all types are resolved before going into IR. 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 8ddab8661df..584df3233fd 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 @@ -403,6 +403,10 @@ impl ty::TyExpression { }; Ok(typed_expr) } + ExpressionKind::Ref(expr) => Self::type_check_ref(handler, ctx.by_ref(), expr, span), + ExpressionKind::Deref(expr) => { + Self::type_check_deref(handler, ctx.by_ref(), expr, span) + } }; let mut typed_expression = match res { Ok(r) => r, @@ -2014,6 +2018,74 @@ impl ty::TyExpression { } } + fn type_check_ref( + handler: &Handler, + mut ctx: TypeCheckContext<'_>, + expr: Box, + span: Span, + ) -> Result { + let engines = ctx.engines(); + let type_engine = ctx.engines().te(); + + // We need to remove the type annotation, because the type expected from the context will + // be the reference type, and we are checking the referenced type. + let ctx = ctx + .by_ref() + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) + .with_help_text(""); + let expr_span = expr.span(); + let expr = ty::TyExpression::type_check(handler, ctx, *expr) + .unwrap_or_else(|err| ty::TyExpression::error(err, expr_span.clone(), engines)); + let expr_type_argument: TypeArgument = expr.return_type.into(); + let typed_expr = ty::TyExpression { + expression: ty::TyExpressionVariant::Ref(Box::new(expr)), + return_type: type_engine.insert(engines, TypeInfo::Ref(expr_type_argument), None), + span, + }; + + Ok(typed_expr) + } + + fn type_check_deref( + handler: &Handler, + mut ctx: TypeCheckContext<'_>, + expr: Box, + span: Span, + ) -> Result { + let engines = ctx.engines(); + let type_engine = ctx.engines().te(); + + // We need to remove the type annotation, because the type expected from the context will + // be the referenced type, and we are checking the reference type. + let ctx = ctx + .by_ref() + .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) + .with_help_text(""); + let expr_span = expr.span(); + let expr = ty::TyExpression::type_check(handler, ctx, *expr) + .unwrap_or_else(|err| ty::TyExpression::error(err, expr_span.clone(), engines)); + + let expr_type = type_engine.get(expr.return_type); + let return_type = match *expr_type { + TypeInfo::ErrorRecovery(_) => Ok(expr.return_type), // Just forward the error return type. + TypeInfo::Ref(ref exp) => Ok(exp.type_id), // Get the referenced type. + _ => Err( + handler.emit_err(CompileError::ExpressionCannotBeDereferenced { + expression_type: engines.help_out(expr.return_type).to_string(), + span: expr_span, + }), + ), + }?; + + let typed_expr = ty::TyExpression { + expression: ty::TyExpressionVariant::Deref(Box::new(expr)), + return_type, + span, + }; + + Ok(typed_expr) + } + fn resolve_numeric_literal( handler: &Handler, ctx: TypeCheckContext, diff --git a/sway-core/src/semantic_analysis/cei_pattern_analysis.rs b/sway-core/src/semantic_analysis/cei_pattern_analysis.rs index 18d8b9a07b8..a27af3209ac 100644 --- a/sway-core/src/semantic_analysis/cei_pattern_analysis.rs +++ b/sway-core/src/semantic_analysis/cei_pattern_analysis.rs @@ -306,7 +306,9 @@ fn analyze_expression( | Return(expr) | EnumTag { exp: expr } | UnsafeDowncast { exp: expr, .. } - | AbiCast { address: expr, .. } => analyze_expression(engines, expr, block_name, warnings), + | AbiCast { address: expr, .. } + | Ref(expr) + | Deref(expr) => analyze_expression(engines, expr, block_name, warnings), EnumInstantiation { contents, .. } => match contents { Some(expr) => analyze_expression(engines, expr, block_name, warnings), None => HashSet::new(), @@ -556,7 +558,9 @@ fn effects_of_expression(engines: &Engines, expr: &ty::TyExpression) -> HashSet< | TupleElemAccess { prefix: expr, .. } | EnumTag { exp: expr } | UnsafeDowncast { exp: expr, .. } - | Return(expr) => effects_of_expression(engines, expr), + | Return(expr) + | Ref(expr) + | Deref(expr) => effects_of_expression(engines, expr), EnumInstantiation { contents, .. } => match contents { Some(expr) => effects_of_expression(engines, expr), None => HashSet::new(), diff --git a/sway-core/src/semantic_analysis/coins_analysis.rs b/sway-core/src/semantic_analysis/coins_analysis.rs index 38ea5b9bf9c..c32b8bce544 100644 --- a/sway-core/src/semantic_analysis/coins_analysis.rs +++ b/sway-core/src/semantic_analysis/coins_analysis.rs @@ -81,6 +81,8 @@ pub fn possibly_nonzero_u64_expression( | Break | Continue | Reassignment(_) - | Return(_) => true, + | Return(_) + | Ref(_) + | Deref(_) => true, } } diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index dc2a2d75fff..79d0f6f1d02 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -614,6 +614,9 @@ impl Dependencies { self.gather_from_expr(engines, &reassignment.rhs) } ExpressionKind::Return(expr) => self.gather_from_expr(engines, expr), + ExpressionKind::Ref(expr) | ExpressionKind::Deref(expr) => { + self.gather_from_expr(engines, expr) + } } } @@ -907,6 +910,7 @@ fn type_info_name(type_info: &TypeInfo) -> String { TypeInfo::Slice(..) => "__slice", TypeInfo::Alias { .. } => "alias", TypeInfo::TraitType { .. } => "trait type", + TypeInfo::Ref(..) => "reference type", } .to_string() } diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index abf74aa39e7..1b1d2a858ff 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -537,6 +537,26 @@ impl<'a> TypeCheckContext<'a> { ))); } } + TypeInfo::Ref(mut ty) => { + ty.type_id = self + .resolve( + handler, + ty.type_id, + span, + enforce_type_arguments, + None, + mod_path, + ) + .unwrap_or_else(|err| { + self.engines + .te() + .insert(self.engines, TypeInfo::ErrorRecovery(err), None) + }); + + self.engines + .te() + .insert(self.engines, TypeInfo::Ref(ty.clone()), None) + } _ => type_id, }; 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 e999f80ff81..b1454a7ed1b 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 @@ -1382,6 +1382,10 @@ fn ty_to_type_info( let type_argument = ty_to_type_argument(context, handler, engines, *ty.into_inner())?; TypeInfo::Slice(type_argument) } + Ty::Ref { ty, .. } => { + let type_argument = ty_to_type_argument(context, handler, engines, *ty)?; + TypeInfo::Ref(type_argument) + } }; Ok(type_info) } @@ -2081,18 +2085,18 @@ fn expr_to_expression( }), span, }, - Expr::Ref { ref_token, .. } => { - let error = ConvertParseTreeError::RefExprNotYetSupported { - span: ref_token.span(), - }; - return Err(handler.emit_err(error.into())); - } - Expr::Deref { deref_token, .. } => { - let error = ConvertParseTreeError::DerefExprNotYetSupported { - span: deref_token.span(), - }; - return Err(handler.emit_err(error.into())); - } + Expr::Ref { expr, .. } => Expression { + kind: ExpressionKind::Ref(Box::new(expr_to_expression( + context, handler, engines, *expr, + )?)), + span, + }, + Expr::Deref { expr, .. } => Expression { + kind: ExpressionKind::Deref(Box::new(expr_to_expression( + context, handler, engines, *expr, + )?)), + span, + }, Expr::Not { bang_token, expr } => { let expr = expr_to_expression(context, handler, engines, *expr)?; op_call("not", bang_token.span(), span, &[expr])? @@ -3804,6 +3808,7 @@ fn ty_to_type_parameter( Ty::StringArray { .. } => panic!("str types are not allowed in this position"), Ty::Ptr { .. } => panic!("__ptr types are not allowed in this position"), Ty::Slice { .. } => panic!("__slice types are not allowed in this position"), + Ty::Ref { .. } => panic!("ref types are not allowed in this position"), }; let custom_type = type_engine.insert( engines, diff --git a/sway-core/src/type_system/engine.rs b/sway-core/src/type_system/engine.rs index 6e3c86bec1b..abc69cb7e58 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -261,6 +261,7 @@ impl TypeEngine { } TypeInfo::Ptr(targ) => self.contains_numeric(decl_engine, targ.type_id), TypeInfo::Slice(targ) => self.contains_numeric(decl_engine, targ.type_id), + TypeInfo::Ref(targ) => self.contains_numeric(decl_engine, targ.type_id), TypeInfo::Unknown | TypeInfo::UnknownGeneric { .. } | TypeInfo::Placeholder(..) @@ -314,6 +315,7 @@ impl TypeEngine { } TypeInfo::Ptr(targ) => self.decay_numeric(handler, engines, targ.type_id, span)?, TypeInfo::Slice(targ) => self.decay_numeric(handler, engines, targ.type_id, span)?, + TypeInfo::Ref(targ) => self.decay_numeric(handler, engines, targ.type_id, span)?, TypeInfo::Unknown | TypeInfo::UnknownGeneric { .. } @@ -367,7 +369,7 @@ impl TypeEngine { } } -/// Maps specific `TypeInfo` variants to a reserved `SourceId`, returning `None` for non-mapped types. +/// Maps specific [TypeInfo] variants to a reserved [SourceId], returning `None` for non-mapped types. fn info_to_source_id(ty: &TypeInfo) -> Option { match ty { TypeInfo::Unknown @@ -380,7 +382,8 @@ fn info_to_source_id(ty: &TypeInfo) -> Option { | TypeInfo::StringSlice | TypeInfo::Contract | TypeInfo::StringArray(_) - | TypeInfo::Array(_, _) => Some(SourceId::reserved()), + | TypeInfo::Array(_, _) + | TypeInfo::Ref(_) => Some(SourceId::reserved()), TypeInfo::Tuple(v) if v.is_empty() => Some(SourceId::reserved()), _ => None, } diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index 1be0f3e8650..37db16cf6c2 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -364,6 +364,13 @@ impl TypeId { .extract_any_including_self(engines, filter_fn, vec![]), ); } + TypeInfo::Ref(ty) => { + extend( + &mut found, + ty.type_id + .extract_any_including_self(engines, filter_fn, vec![]), + ); + } } found } diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index 7d7c87e3d72..66067478781 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -184,6 +184,7 @@ pub enum TypeInfo { name: Ident, trait_type_id: TypeId, }, + Ref(TypeArgument), } impl HashWithEngines for TypeInfo { @@ -262,6 +263,9 @@ impl HashWithEngines for TypeInfo { name.hash(state); trait_type_id.hash(state); } + TypeInfo::Ref(ty) => { + ty.hash(state, engines); + } TypeInfo::StringSlice | TypeInfo::Numeric | TypeInfo::Boolean @@ -334,9 +338,10 @@ impl PartialEqWithEngines for TypeInfo { .iter() .zip(r.iter()) .map(|(l, r)| { - type_engine - .get(l.type_id) - .eq(&type_engine.get(r.type_id), engines) + (l.type_id == r.type_id) + || type_engine + .get(l.type_id) + .eq(&type_engine.get(r.type_id), engines) }) .all(|x| x), ( @@ -352,9 +357,10 @@ impl PartialEqWithEngines for TypeInfo { l_abi_name == r_abi_name && l_address.as_deref().eq(&r_address.as_deref(), engines) } (Self::Array(l0, l1), Self::Array(r0, r1)) => { - type_engine - .get(l0.type_id) - .eq(&type_engine.get(r0.type_id), engines) + ((l0.type_id == r0.type_id) + || type_engine + .get(l0.type_id) + .eq(&type_engine.get(r0.type_id), engines)) && l1.val() == r1.val() } (TypeInfo::Storage { fields: l_fields }, TypeInfo::Storage { fields: r_fields }) => { @@ -371,9 +377,10 @@ impl PartialEqWithEngines for TypeInfo { }, ) => { l_name == r_name - && type_engine - .get(l_ty.type_id) - .eq(&type_engine.get(r_ty.type_id), engines) + && ((l_ty.type_id == r_ty.type_id) + || type_engine + .get(l_ty.type_id) + .eq(&type_engine.get(r_ty.type_id), engines)) } ( TypeInfo::TraitType { @@ -386,10 +393,18 @@ impl PartialEqWithEngines for TypeInfo { }, ) => { l_name == r_name - && type_engine - .get(*l_trait_type_id) - .eq(&type_engine.get(*r_trait_type_id), engines) + && ((*l_trait_type_id == *r_trait_type_id) + || type_engine + .get(*l_trait_type_id) + .eq(&type_engine.get(*r_trait_type_id), engines)) } + (Self::Ref(l_ty), Self::Ref(r_ty)) => { + (l_ty.type_id == r_ty.type_id) + || type_engine + .get(l_ty.type_id) + .eq(&type_engine.get(r_ty.type_id), engines) + } + (l, r) => l.discriminant_value() == r.discriminant_value(), } } @@ -501,6 +516,9 @@ impl OrdWithEngines for TypeInfo { ) => l_trait_type_id .cmp(r_trait_type_id) .then_with(|| l_name.cmp(r_name)), + (Self::Ref(l_ty), Self::Ref(r_ty)) => type_engine + .get(l_ty.type_id) + .cmp(&type_engine.get(r_ty.type_id), engines), (l, r) => l.discriminant_value().cmp(&r.discriminant_value()), } @@ -575,6 +593,9 @@ impl DisplayWithEngines for TypeInfo { name, trait_type_id, } => format!("trait type {}::{}", engines.help_out(trait_type_id), name), + Ref(ty) => { + format!("&{}", engines.help_out(ty)) + } }; write!(f, "{s}") } @@ -675,6 +696,9 @@ impl DebugWithEngines for TypeInfo { name, trait_type_id, } => format!("trait type {}::{}", engines.help_out(trait_type_id), name), + Ref(ty) => { + format!("&{:?}", engines.help_out(ty)) + } }; write!(f, "{s}") } @@ -712,6 +736,7 @@ impl TypeInfo { TypeInfo::Slice(..) => 22, TypeInfo::StringSlice => 23, TypeInfo::TraitType { .. } => 24, + TypeInfo::Ref { .. } => 25, } } @@ -918,6 +943,8 @@ impl TypeInfo { .to_selector_name(handler, engines, error_msg_span); name? } + // TODO-IG: No references in ABIs according to the RFC. Or we want to have them? + // TODO-IG: Depending on that, we need to handle `Ref` here as well. _ => { return Err(handler.emit_err(CompileError::InvalidAbiType { span: error_msg_span.clone(), @@ -1033,6 +1060,7 @@ impl TypeInfo { } } + // TODO-IG: Check all the usages of `is_copy_type`. pub fn is_copy_type(&self) -> bool { // XXX This is FuelVM specific. We need to find the users of this method and determine // whether they're actually asking 'is_aggregate()` or something else. @@ -1044,7 +1072,7 @@ impl TypeInfo { | TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo) | TypeInfo::UnsignedInteger(IntegerBits::SixtyFour) | TypeInfo::RawUntypedPtr - | TypeInfo::Numeric + | TypeInfo::Numeric // TODO-IG: Should Ptr and Ref also be a copy type? ) || self.is_unit() } @@ -1056,6 +1084,10 @@ impl TypeInfo { } } + pub fn is_reference_type(&self) -> bool { + matches!(self, TypeInfo::Ref(_)) + } + pub(crate) fn apply_type_arguments( self, handler: &Handler, @@ -1101,8 +1133,8 @@ impl TypeInfo { | TypeInfo::Numeric | TypeInfo::RawUntypedPtr | TypeInfo::RawUntypedSlice - | TypeInfo::Ptr(..) - | TypeInfo::Slice(..) + | TypeInfo::Ptr(_) + | TypeInfo::Slice(_) | TypeInfo::Contract | TypeInfo::ErrorRecovery(_) | TypeInfo::Array(_, _) @@ -1110,13 +1142,14 @@ impl TypeInfo { | TypeInfo::Placeholder(_) | TypeInfo::TypeParam(_) | TypeInfo::Alias { .. } - | TypeInfo::TraitType { .. } => { + | TypeInfo::TraitType { .. } + | TypeInfo::Ref(_) => { Err(handler.emit_err(CompileError::TypeArgumentsNotAllowed { span: span.clone() })) } } } - /// Given a `TypeInfo` `self`, check to see if `self` is currently + /// Given a [TypeInfo] `self`, check to see if `self` is currently /// supported in match expressions, and return an error if it is not. pub(crate) fn expect_is_supported_in_match_expressions( &self, @@ -1148,14 +1181,19 @@ impl TypeInfo { | TypeInfo::Placeholder(_) | TypeInfo::TypeParam(_) | TypeInfo::TraitType { .. } => Err(handler.emit_err(CompileError::Unimplemented( - "matching on this type is unsupported right now", + "Matching on this type is currently not supported.", + span.clone(), + ))), + TypeInfo::Ref(_) => Err(handler.emit_err(CompileError::Unimplemented( + // TODO-IG: Implement. + "Using references in match expressions is currently not supported.", span.clone(), ))), TypeInfo::ErrorRecovery(err) => Err(*err), } } - /// Given a `TypeInfo` `self`, check to see if `self` is currently + /// Given a [TypeInfo] `self`, check to see if `self` is currently /// supported in `impl` blocks in the "type implementing for" position. pub(crate) fn expect_is_supported_in_impl_blocks_self( &self, @@ -1185,7 +1223,8 @@ impl TypeInfo { | TypeInfo::Numeric | TypeInfo::Alias { .. } | TypeInfo::UnknownGeneric { .. } - | TypeInfo::TraitType { .. } => Ok(()), + | TypeInfo::TraitType { .. } + | TypeInfo::Ref(_) => Ok(()), TypeInfo::Unknown | TypeInfo::ContractCaller { .. } | TypeInfo::Storage { .. } @@ -1198,7 +1237,7 @@ impl TypeInfo { } } - /// Given a `TypeInfo` `self` and a list of `Ident`'s `subfields`, + /// Given a [TypeInfo] `self` and a list of [Ident]'s `subfields`, /// iterate through the elements of `subfields` as `subfield`, /// and recursively apply `subfield` to `self`. /// @@ -1206,7 +1245,7 @@ impl TypeInfo { /// applied without error. /// /// Returns an error when subfields could not be applied: - /// 1) in the case where `self` is not a `TypeInfo::Struct` + /// 1) in the case where `self` is not a [TypeInfo::Struct] /// 2) in the case where `subfields` is empty /// 3) in the case where a `subfield` does not exist on `self` pub(crate) fn apply_subfields( @@ -1264,6 +1303,7 @@ impl TypeInfo { .get(*type_id) .apply_subfields(handler, engines, subfields, span), (TypeInfo::ErrorRecovery(err), _) => Err(*err), + // TODO-IG: Take a close look on this when implementing dereferencing. (type_info, _) => Err(handler.emit_err(CompileError::FieldAccessOnNonStruct { actually: format!("{:?}", engines.help_out(type_info)), span: span.clone(), @@ -1290,8 +1330,8 @@ impl TypeInfo { | TypeInfo::B256 | TypeInfo::RawUntypedPtr | TypeInfo::RawUntypedSlice - | TypeInfo::Ptr(..) - | TypeInfo::Slice(..) + | TypeInfo::Ptr(_) + | TypeInfo::Slice(_) | TypeInfo::ErrorRecovery(_) | TypeInfo::TraitType { .. } => false, TypeInfo::Unknown @@ -1305,7 +1345,8 @@ impl TypeInfo { | TypeInfo::Numeric | TypeInfo::Placeholder(_) | TypeInfo::TypeParam(_) - | TypeInfo::Alias { .. } => true, + | TypeInfo::Alias { .. } + | TypeInfo::Ref(_) => true, } } @@ -1321,8 +1362,8 @@ impl TypeInfo { } } - /// Given a `TypeInfo` `self`, expect that `self` is a `TypeInfo::Tuple`, or a - /// `TypeInfo::Alias` of a tuple type. Also, return the contents of the tuple. + /// Given a [TypeInfo] `self`, expect that `self` is a [TypeInfo::Tuple], or a + /// [TypeInfo::Alias] of a tuple type. Also, return the contents of the tuple. /// /// Note that this works recursively. That is, it supports situations where a tuple has a chain /// of aliases such as: @@ -1336,7 +1377,7 @@ impl TypeInfo { /// } /// ``` /// - /// Returns an error if `self` is not a `TypeInfo::Tuple` or a `TypeInfo::Alias` of a tuple + /// Returns an error if `self` is not a [TypeInfo::Tuple] or a [TypeInfo::Alias] of a tuple /// type, transitively. pub(crate) fn expect_tuple( &self, @@ -1365,7 +1406,7 @@ impl TypeInfo { } } - /// Given a `TypeInfo` `self`, expect that `self` is a `TypeInfo::Enum`, or a `TypeInfo::Alias` + /// Given a [TypeInfo] `self`, expect that `self` is a [TypeInfo::Enum], or a [TypeInfo::Alias] /// of a enum type. Also, return the contents of the enum. /// /// Note that this works recursively. That is, it supports situations where a enum has a chain @@ -1379,7 +1420,7 @@ impl TypeInfo { /// let e = Alias2::X; /// ``` /// - /// Returns an error if `self` is not a `TypeInfo::Enum` or a `TypeInfo::Alias` of a enum type, + /// Returns an error if `self` is not a [TypeInfo::Enum] or a [TypeInfo::Alias] of a enum type, /// transitively. pub(crate) fn expect_enum( &self, @@ -1406,8 +1447,8 @@ impl TypeInfo { } } - /// Given a `TypeInfo` `self`, expect that `self` is a `TypeInfo::Struct`, or a - /// `TypeInfo::Alias` of a struct type. Also, return the contents of the struct. + /// Given a [TypeInfo] `self`, expect that `self` is a [TypeInfo::Struct], or a + /// [TypeInfo::Alias] of a struct type. Also, return the contents of the struct. /// /// Note that this works recursively. That is, it supports situations where a struct has a /// chain of aliases such as: @@ -1420,7 +1461,7 @@ impl TypeInfo { /// let s = Alias2 { x: 0 }; /// ``` /// - /// Returns an error if `self` is not a `TypeInfo::Struct` or a `TypeInfo::Alias` of a struct + /// Returns an error if `self` is not a [TypeInfo::Struct] or a [TypeInfo::Alias] of a struct /// type, transitively. #[allow(dead_code)] pub(crate) fn expect_struct( diff --git a/sway-core/src/type_system/substitute/subst_map.rs b/sway-core/src/type_system/substitute/subst_map.rs index 12fac7b2109..c0ef71dcc15 100644 --- a/sway-core/src/type_system/substitute/subst_map.rs +++ b/sway-core/src/type_system/substitute/subst_map.rs @@ -314,18 +314,21 @@ impl TypeSubstMap { /// Given a [TypeId] `type_id`, find (or create) a match for `type_id` in /// this [TypeSubstMap] and return it, if there is a match. Importantly, this /// function is recursive, so any `type_id` it's given will undergo - /// recursive calls this function. For instance, in the case of + /// recursive calls of this function. For instance, in the case of /// [TypeInfo::Struct], both `fields` and `type_parameters` will recursively /// call `find_match` (via calling [SubstTypes]). /// - /// A match can be found in two different circumstances: - /// - `type_id` is a [TypeInfo::Custom] or [TypeInfo::UnknownGeneric] + /// A match can be found in these circumstances: + /// - `type_id` is one of the following: [TypeInfo::Custom], + /// [TypeInfo::UnknownGeneric], [TypeInfo::Placeholder], or [TypeInfo::TraitType]. /// - /// A match is potentially created (i.e. a new `TypeId` is created) in these + /// A match is potentially created (i.e. a new [TypeId] is created) in these /// circumstances: - /// - `type_id` is a [TypeInfo::Struct], [TypeInfo::Enum], - /// [TypeInfo::Array], or [TypeInfo::Tuple] and one of the sub-types - /// finds a match in a recursive call to `find_match` + /// - `type_id` is one of the following: [TypeInfo::Struct], [TypeInfo::Enum], + /// [TypeInfo::Array], [TypeInfo::Tuple], [TypeInfo::Storage], [TypeInfo::Alias], + /// [TypeInfo::Alias], [TypeInfo::Ptr], [TypeInfo::Slice], or [TypeInfo::Ref], + /// and one of the contained types (e.g. a struct field, or a referenced type) + /// finds a match in a recursive call to `find_match`. /// /// A match cannot be found in any other circumstance. pub(crate) fn find_match(&self, type_id: TypeId, engines: &Engines) -> Option { @@ -468,6 +471,10 @@ impl TypeSubstMap { type_engine.insert(engines, TypeInfo::Slice(ty.clone()), ty.span.source_id()) }), TypeInfo::TraitType { .. } => iter_for_match(engines, self, &type_info), + TypeInfo::Ref(mut ty) => self.find_match(ty.type_id, engines).map(|type_id| { + ty.type_id = type_id; + type_engine.insert(engines, TypeInfo::Ref(ty.clone()), ty.span.source_id()) + }), TypeInfo::Unknown | TypeInfo::StringArray(..) | TypeInfo::StringSlice diff --git a/sway-core/src/type_system/unify/unifier.rs b/sway-core/src/type_system/unify/unifier.rs index 258c5201cdc..eaf31f21900 100644 --- a/sway-core/src/type_system/unify/unifier.rs +++ b/sway-core/src/type_system/unify/unifier.rs @@ -113,7 +113,7 @@ impl<'a> Unifier<'a> { self.unify_tuples(handler, rfs, efs) } (Array(re, rc), Array(ee, ec)) if rc.val() == ec.val() => { - self.unify_arrays(handler, received, expected, span, re.type_id, ee.type_id) + self.unify_type_arguments_in_parents(handler, received, expected, span, re, ee) } (Struct(r_decl_ref), Struct(e_decl_ref)) => { let r_decl = self.engines.de().get_struct(r_decl_ref); @@ -260,6 +260,9 @@ impl<'a> Unifier<'a> { { // if they are the same, then it's ok } + (Ref(r), Ref(e)) => { + self.unify_type_arguments_in_parents(handler, received, expected, span, r, e) + } // If no previous attempts to unify were successful, raise an error. (TypeInfo::ErrorRecovery(_), _) => (), @@ -386,23 +389,32 @@ impl<'a> Unifier<'a> { } } - fn unify_arrays( + /// Unifies `received_type_argument` and `expected_type_argument`, and in case of a + /// mismatch, reports the `received_parent` and `expected_parent` as mismatching. + /// Useful for unifying types like arrays and references where issues in unification + /// of their [TypeArgument]s directly corresponds to the unification of enclosed types themselves. + fn unify_type_arguments_in_parents( &self, handler: &Handler, - received: TypeId, - expected: TypeId, + received_parent: TypeId, + expected_parent: TypeId, span: &Span, - r: TypeId, - e: TypeId, + received_type_argument: &TypeArgument, + expected_type_argument: &TypeArgument, ) { let h = Handler::default(); - self.unify(&h, r, e, span); + self.unify( + &h, + received_type_argument.type_id, + expected_type_argument.type_id, + span, + ); let (new_errors, warnings) = h.consume(); - // If there was an error then we want to report the array types as mismatching, not - // the elem types. + // If there was an error then we want to report the parent types as mismatching, not + // the argument types. if !new_errors.is_empty() { - let (received, expected) = self.assign_args(received, expected); + let (received, expected) = self.assign_args(received_parent, expected_parent); handler.emit_err( TypeError::MismatchedType { expected, diff --git a/sway-core/src/type_system/unify/unify_check.rs b/sway-core/src/type_system/unify/unify_check.rs index 263224368d6..fe62a2c2373 100644 --- a/sway-core/src/type_system/unify/unify_check.rs +++ b/sway-core/src/type_system/unify/unify_check.rs @@ -325,6 +325,11 @@ impl<'a> UnifyCheck<'a> { && self.check_multiple(&l_types, &r_types) && self.check_multiple(&l_root_type_ids, &r_root_type_ids); } + + (Ref(l_ty), Ref(r_ty)) => { + return self.check_inner(l_ty.type_id, r_ty.type_id); + } + _ => {} } @@ -486,7 +491,7 @@ impl<'a> UnifyCheck<'a> { } } NonDynamicEquality => match (&*left_info, &*right_info) { - // when a type alias is encoutered, defer the decision to the type it contains (i.e. the + // when a type alias is encountered, defer the decision to the type it contains (i.e. the // type it aliases with) (Alias { ty, .. }, _) => self.check_inner(ty.type_id, right), (_, Alias { ty, .. }) => self.check_inner(left, ty.type_id), diff --git a/sway-error/src/convert_parse_tree_error.rs b/sway-error/src/convert_parse_tree_error.rs index dd3b76c8aa8..8bc84c100e0 100644 --- a/sway-error/src/convert_parse_tree_error.rs +++ b/sway-error/src/convert_parse_tree_error.rs @@ -105,10 +105,6 @@ pub enum ConvertParseTreeError { CannotAnnotateDependency { span: Span }, #[error("Expected dependency at the beginning before any other items.")] ExpectedDependencyAtBeginning { span: Span }, - #[error("Ref expressions are not supported yet.")] - RefExprNotYetSupported { span: Span }, - #[error("Deref expressions are not supported yet.")] - DerefExprNotYetSupported { span: Span }, #[error("Constant requires expression.")] ConstantRequiresExpression { span: Span }, #[error("Constant requires type ascription.")] @@ -177,8 +173,6 @@ impl Spanned for ConvertParseTreeError { ConvertParseTreeError::CannotDocCommentDependency { span } => span.clone(), ConvertParseTreeError::CannotAnnotateDependency { span } => span.clone(), ConvertParseTreeError::ExpectedDependencyAtBeginning { span } => span.clone(), - ConvertParseTreeError::RefExprNotYetSupported { span } => span.clone(), - ConvertParseTreeError::DerefExprNotYetSupported { span } => span.clone(), ConvertParseTreeError::ConstantRequiresExpression { span } => span.clone(), ConvertParseTreeError::ConstantRequiresTypeAscription { span } => span.clone(), ConvertParseTreeError::InvalidCfgTargetArgValue { span, .. } => span.clone(), diff --git a/sway-error/src/error.rs b/sway-error/src/error.rs index 1e8f4a56497..46f4fa3d8c1 100644 --- a/sway-error/src/error.rs +++ b/sway-error/src/error.rs @@ -751,9 +751,10 @@ pub enum CompileError { AbiSupertraitMethodCallAsContractCall { fn_name: Ident, span: Span }, #[error("\"Self\" is not valid in the self type of an impl block")] SelfIsNotValidAsImplementingFor { span: Span }, - - #[error("Unitialized register is being read before being written")] + #[error("Uninitialized register is being read before being written")] UninitRegisterInAsmBlockBeingRead { span: Span }, + #[error("Expression of type \"{expression_type}\" cannot be dereferenced.")] + ExpressionCannotBeDereferenced { expression_type: String, span: Span }, } impl std::convert::From for CompileError { @@ -946,6 +947,7 @@ impl Spanned for CompileError { ExpectedStringLiteral { span } => span.clone(), SelfIsNotValidAsImplementingFor { span } => span.clone(), UninitRegisterInAsmBlockBeingRead { span } => span.clone(), + ExpressionCannotBeDereferenced { span, .. } => span.clone(), } } } @@ -1142,91 +1144,115 @@ impl ToDiagnostic for CompileError { // Make candidates order deterministic let mut trait_candidates = trait_candidates.clone(); trait_candidates.sort(); - let trait_candidates = &trait_candidates; - Diagnostic { - reason: Some(Reason::new(code(1), "Trait is not imported".to_string())), - issue: Issue::error( - source_engine, - function_call_site_span.clone(), - format!( - "Trait \"{trait_name}\" is not imported {}when calling \"{function_name}\".", - get_file_name(source_engine, function_call_site_span.source_id()) - .map_or("".to_string(), |file_name| format!("into \"{file_name}\" ")) - ) - ), - hints: { - let mut hints = vec![ - Hint::help( - source_engine, - function_call_site_span.clone(), - format!("This import is needed because \"{function_name}\" requires \"{trait_name}\" in one of its trait constraints.") - ), - Hint::info( - source_engine, - trait_constraint_span.clone(), - format!("In the definition of \"{function_name}\", \"{trait_name}\" is used in this trait constraint.") - ), - ]; + let trait_candidates = &trait_candidates; // Remove mutability. - match trait_candidates.len() { - // If no candidates are found, that means that an alias was used in the trait constraint definition. - // The way how constraint checking works now, the trait will not be found when we try to check if - // the trait constraints are satisfied for type, and we will never end up in this case here. - // So we will simply ignore it. - 0 => (), - // The most common case. Exactly one known trait with the given name. - 1 => hints.push(Hint::help( + Diagnostic { + reason: Some(Reason::new(code(1), "Trait is not imported".to_string())), + issue: Issue::error( + source_engine, + function_call_site_span.clone(), + format!( + "Trait \"{trait_name}\" is not imported {}when calling \"{function_name}\".", + get_file_name(source_engine, function_call_site_span.source_id()) + .map_or("".to_string(), |file_name| format!("into \"{file_name}\" ")) + ) + ), + hints: { + let mut hints = vec![ + Hint::help( source_engine, function_call_site_span.clone(), - format!( - "Import the \"{trait_name}\" trait {}by using: `use {};`.", - get_file_name(source_engine, function_call_site_span.source_id()) - .map_or("".to_string(), |file_name| format!("into \"{file_name}\" ")), - trait_candidates[0] - ) - )), - // Unlikely (for now) case of having several traits with the same name. - _ => hints.push(Hint::help( + format!("This import is needed because \"{function_name}\" requires \"{trait_name}\" in one of its trait constraints.") + ), + Hint::info( source_engine, - function_call_site_span.clone(), - format!( - "To import the proper \"{trait_name}\" {}follow the detailed instructions given below.", - get_file_name(source_engine, function_call_site_span.source_id()) - .map_or("".to_string(), |file_name| format!("into \"{file_name}\" ")) - ) - )), - } + trait_constraint_span.clone(), + format!("In the definition of \"{function_name}\", \"{trait_name}\" is used in this trait constraint.") + ), + ]; - hints - }, - help: { - let mut help = vec![]; + match trait_candidates.len() { + // If no candidates are found, that means that an alias was used in the trait constraint definition. + // The way how constraint checking works now, the trait will not be found when we try to check if + // the trait constraints are satisfied for type, and we will never end up in this case here. + // So we will simply ignore it. + 0 => (), + // The most common case. Exactly one known trait with the given name. + 1 => hints.push(Hint::help( + source_engine, + function_call_site_span.clone(), + format!( + "Import the \"{trait_name}\" trait {}by using: `use {};`.", + get_file_name(source_engine, function_call_site_span.source_id()) + .map_or("".to_string(), |file_name| format!("into \"{file_name}\" ")), + trait_candidates[0] + ) + )), + // Unlikely (for now) case of having several traits with the same name. + _ => hints.push(Hint::help( + source_engine, + function_call_site_span.clone(), + format!( + "To import the proper \"{trait_name}\" {}follow the detailed instructions given below.", + get_file_name(source_engine, function_call_site_span.source_id()) + .map_or("".to_string(), |file_name| format!("into \"{file_name}\" ")) + ) + )), + } - if trait_candidates.len() > 1 { - help.push(format!("There are these {} traits with the name \"{trait_name}\" available in the modules:", trait_candidates.len())); - for trait_candidate in trait_candidates.iter() { - help.push(format!(" - {trait_candidate}")); + hints + }, + help: { + let mut help = vec![]; + + if trait_candidates.len() > 1 { + help.push(format!("There are these {} traits with the name \"{trait_name}\" available in the modules:", trait_candidates.len())); + for trait_candidate in trait_candidates.iter() { + help.push(format!(" - {trait_candidate}")); + } + help.push("To import the proper one follow these steps:".to_string()); + help.push(format!( + " 1. Look at the definition of the \"{function_name}\"{}.", + get_file_name(source_engine, trait_constraint_span.source_id()) + .map_or("".to_string(), |file_name| format!(" in the \"{file_name}\"")) + )); + help.push(format!( + " 2. Detect which exact \"{trait_name}\" is used in the trait constraint in the \"{function_name}\"." + )); + help.push(format!( + " 3. Import that \"{trait_name}\"{}.", + get_file_name(source_engine, function_call_site_span.source_id()) + .map_or("".to_string(), |file_name| format!(" into \"{file_name}\"")) + )); + help.push(format!(" E.g., assuming it is the first one on the list, use: `use {};`", trait_candidates[0])); } - help.push("To import the proper one follow these steps:".to_string()); - help.push(format!( - " 1. Look at the definition of the \"{function_name}\"{}.", - get_file_name(source_engine, trait_constraint_span.source_id()) - .map_or("".to_string(), |file_name| format!(" in the \"{file_name}\"")) - )); - help.push(format!( - " 2. Detect which exact \"{trait_name}\" is used in the trait constraint in the \"{function_name}\"." - )); - help.push(format!( - " 3. Import that \"{trait_name}\"{}.", - get_file_name(source_engine, function_call_site_span.source_id()) - .map_or("".to_string(), |file_name| format!(" into \"{file_name}\"")) - )); - help.push(format!(" E.g., assuming it is the first one on the list, use: `use {};`", trait_candidates[0])); - } - help - }, - }}, + help + }, + } + }, + // TODO-IG: Extend error messages to pointers, once typed pointers are defined and can be dereferenced. + ExpressionCannotBeDereferenced { expression_type, span } => Diagnostic { + reason: Some(Reason::new(code(1), "Expression cannot be dereferenced".to_string())), + issue: Issue::error( + source_engine, + span.clone(), + format!("This expression cannot be dereferenced, because it is of type \"{expression_type}\", which is not a reference type.") + ), + hints: vec![ + Hint::help( + source_engine, + span.clone(), + "In Sway, only references can be dereferenced.".to_string() + ), + Hint::help( + source_engine, + span.clone(), + "Are you missing the reference operator `&` somewhere in the code?".to_string() + ), + ], + help: vec![], + }, _ => Diagnostic { // TODO: Temporary we use self here to achieve backward compatibility. // In general, self must not be used and will not be used once we diff --git a/sway-ir/src/constant.rs b/sway-ir/src/constant.rs index bc107ed0e62..87855825884 100644 --- a/sway-ir/src/constant.rs +++ b/sway-ir/src/constant.rs @@ -24,6 +24,7 @@ pub enum ConstantValue { String(Vec), Array(Vec), Struct(Vec), + Reference(Box), } /// A [Constant] with its required [Padding]. diff --git a/sway-ir/src/error.rs b/sway-ir/src/error.rs index 6568d32e132..44fa75b1892 100644 --- a/sway-ir/src/error.rs +++ b/sway-ir/src/error.rs @@ -240,7 +240,7 @@ impl fmt::Display for IrError { IrError::VerifyLoadFromNonPointer(ty) => { write!( f, - "Verification failed: Load cannot be from a non-pinter {ty}." + "Verification failed: Load cannot be from a non-pointer {ty}." ) } IrError::VerifyMemcopyNonPointer(ty) => { diff --git a/sway-ir/src/irtype.rs b/sway-ir/src/irtype.rs index 6d9ff4cd4e5..eeddd170dd7 100644 --- a/sway-ir/src/irtype.rs +++ b/sway-ir/src/irtype.rs @@ -59,7 +59,7 @@ impl Type { Self::get_or_create_unique_type(context, TypeContent::Slice); } - /// Get the content for this Type. + /// Get the content for this [Type]. pub fn get_content<'a>(&self, context: &'a Context) -> &'a TypeContent { &context.types[self.0] } @@ -199,7 +199,6 @@ impl Type { (TypeContent::Union(l), _) => l.iter().any(|field_ty| other.eq(context, field_ty)), (TypeContent::Slice, TypeContent::Slice) => true, (TypeContent::Pointer(l), TypeContent::Pointer(r)) => l.eq(context, r), - _ => false, } } @@ -293,17 +292,18 @@ impl Type { self.is_struct(context) || self.is_union(context) || self.is_array(context) } - /// Returns true if this is a slice type. + /// Returns true if `self` is a slice type. pub fn is_slice(&self, context: &Context) -> bool { matches!(*self.get_content(context), TypeContent::Slice) } - /// Returns true if this is a pointer type. + // TODO-IG: Check all the usages of `is_ptr`. + /// Returns true if `self` is a pointer type. pub fn is_ptr(&self, context: &Context) -> bool { matches!(*self.get_content(context), TypeContent::Pointer(_)) } - /// Get pointed to type iff self is a Pointer. + /// Get pointed to type iff `self`` is a pointer. pub fn get_pointee_type(&self, context: &Context) -> Option { if let TypeContent::Pointer(to_ty) = self.get_content(context) { Some(*to_ty) diff --git a/sway-ir/src/optimize/target_fuel.rs b/sway-ir/src/optimize/target_fuel.rs index 897d72013e4..24652625acd 100644 --- a/sway-ir/src/optimize/target_fuel.rs +++ b/sway-ir/src/optimize/target_fuel.rs @@ -4,7 +4,7 @@ use crate::{ irtype::{Type, TypeContent}, }; -/// Return whether a `Type` _cannot_ fit in a Fuel VM register and requires 'demotion'. +/// Return whether a [Type] _cannot_ fit in a Fuel VM register and requires 'demotion'. pub(super) fn is_demotable_type(context: &Context, ty: &Type) -> bool { match ty.get_content(context) { TypeContent::Unit | TypeContent::Bool | TypeContent::Pointer(_) => false, diff --git a/sway-ir/src/printer.rs b/sway-ir/src/printer.rs index c8b20f44a14..241765a89c6 100644 --- a/sway-ir/src/printer.rs +++ b/sway-ir/src/printer.rs @@ -1097,6 +1097,7 @@ impl Constant { .collect::>() .join(", ") ), + ConstantValue::Reference(constant) => format!("&({})", constant.as_lit_string(context)), } } } diff --git a/sway-ir/src/value.rs b/sway-ir/src/value.rs index e84bce84455..43da63a6a5b 100644 --- a/sway-ir/src/value.rs +++ b/sway-ir/src/value.rs @@ -1,9 +1,9 @@ //! The base descriptor for various values within the IR. //! -//! [`Value`]s can be function arguments, constants and instructions. [`Instruction`]s generally +//! [`Value`]s can be function arguments, constants and instructions. [`Instruction`]s generally //! refer to each other and to constants via the [`Value`] wrapper. //! -//! Like most IR data structures they are `Copy` and cheap to pass around by value. They are +//! Like most IR data structures they are `Copy` and cheap to pass around by value. They are //! therefore also easy to replace, a common practice for optimization passes. use rustc_hash::FxHashMap; diff --git a/sway-ir/src/verify.rs b/sway-ir/src/verify.rs index d1a69af9d1d..b8d876d4a0b 100644 --- a/sway-ir/src/verify.rs +++ b/sway-ir/src/verify.rs @@ -805,7 +805,7 @@ impl<'a, 'eng> InstructionVerifier<'a, 'eng> { } fn verify_load(&self, src_val: &Value) -> Result<(), IrError> { - // Just confirm src_val is a pointer. + // Just confirm `src_val` is a pointer. self.get_ptr_type(src_val, IrError::VerifyLoadFromNonPointer) .map(|_| ()) } diff --git a/sway-lib-core/src/raw_ptr.sw b/sway-lib-core/src/raw_ptr.sw index 5b8d487fc8d..1b4eb513397 100644 --- a/sway-lib-core/src/raw_ptr.sw +++ b/sway-lib-core/src/raw_ptr.sw @@ -79,7 +79,7 @@ impl raw_ptr { /// /// # Returns /// - /// * [T] - The value in memory at the location of the pointer. + /// * [T] - The copy of the value in memory at the location of the pointer. /// /// # Examples /// @@ -263,7 +263,7 @@ impl raw_ptr { /// let ptr = alloc::(2); /// let offset_ptr_1 = ptr.add::(1); /// let offset_ptr_2 = ptr.add_uint_offset(1); - /// assert(offset_ptr_1 == offset_ptr_1); + /// assert(offset_ptr_1 == offset_ptr_2); /// } /// ``` pub fn add_uint_offset(self, offset: u64) -> Self { diff --git a/sway-lsp/src/traverse/lexed_tree.rs b/sway-lsp/src/traverse/lexed_tree.rs index b4ec5328c12..84fa0009d95 100644 --- a/sway-lsp/src/traverse/lexed_tree.rs +++ b/sway-lsp/src/traverse/lexed_tree.rs @@ -207,12 +207,10 @@ impl Parse for Expr { Expr::TupleFieldProjection { target, .. } => { target.parse(ctx); } - Expr::Ref { ref_token, expr } => { - insert_keyword(ctx, ref_token.span()); + Expr::Ref { expr, .. } => { expr.parse(ctx); } - Expr::Deref { deref_token, expr } => { - insert_keyword(ctx, deref_token.span()); + Expr::Deref { expr, .. } => { expr.parse(ctx); } Expr::Not { expr, .. } => { diff --git a/sway-lsp/src/traverse/parsed_tree.rs b/sway-lsp/src/traverse/parsed_tree.rs index de4e721e34a..183e41007e2 100644 --- a/sway-lsp/src/traverse/parsed_tree.rs +++ b/sway-lsp/src/traverse/parsed_tree.rs @@ -344,6 +344,9 @@ impl Parse for Expression { ExpressionKind::Return(expr) => { expr.parse(ctx); } + ExpressionKind::Ref(expr) | ExpressionKind::Deref(expr) => { + expr.parse(ctx); + } // We are collecting these tokens in the lexed phase. ExpressionKind::Break | ExpressionKind::Continue => {} } diff --git a/sway-lsp/src/traverse/typed_tree.rs b/sway-lsp/src/traverse/typed_tree.rs index b1f4c732dee..02a7a18607c 100644 --- a/sway-lsp/src/traverse/typed_tree.rs +++ b/sway-lsp/src/traverse/typed_tree.rs @@ -593,6 +593,9 @@ impl Parse for ty::TyExpression { reassignment.parse(ctx); } ty::TyExpressionVariant::Return(exp) => exp.parse(ctx), + ty::TyExpressionVariant::Ref(exp) | ty::TyExpressionVariant::Deref(exp) => { + exp.parse(ctx) + } } } } diff --git a/sway-parse/src/expr/mod.rs b/sway-parse/src/expr/mod.rs index f976c0be091..b23962c7e76 100644 --- a/sway-parse/src/expr/mod.rs +++ b/sway-parse/src/expr/mod.rs @@ -507,11 +507,14 @@ fn parse_mul(parser: &mut Parser, ctx: ParseExprCtx) -> ParseResult { } fn parse_unary_op(parser: &mut Parser, ctx: ParseExprCtx) -> ParseResult { - if let Some((ref_token, expr)) = parse_op_rhs(parser, ctx, parse_unary_op)? { - return Ok(Expr::Ref { ref_token, expr }); + if let Some((ampersand_token, expr)) = parse_op_rhs(parser, ctx, parse_unary_op)? { + return Ok(Expr::Ref { + ampersand_token, + expr, + }); } - if let Some((deref_token, expr)) = parse_op_rhs(parser, ctx, parse_unary_op)? { - return Ok(Expr::Deref { deref_token, expr }); + if let Some((star_token, expr)) = parse_op_rhs(parser, ctx, parse_unary_op)? { + return Ok(Expr::Deref { star_token, expr }); } if let Some((bang_token, expr)) = parse_op_rhs(parser, ctx, parse_unary_op)? { return Ok(Expr::Not { bang_token, expr }); diff --git a/sway-parse/src/item/item_impl.rs b/sway-parse/src/item/item_impl.rs index de2902b485b..a6b6f55afb7 100644 --- a/sway-parse/src/item/item_impl.rs +++ b/sway-parse/src/item/item_impl.rs @@ -105,4 +105,24 @@ mod tests { ); assert_matches!(item.ty, Ty::Slice { .. }); } + + #[test] + fn parse_impl_ref() { + let item = parse::( + r#" + impl &T {} + "#, + ); + assert_matches!(item.ty, Ty::Ref { .. }); + } + + #[test] + fn parse_impl_for_ref() { + let item = parse::( + r#" + impl Foo for &T {} + "#, + ); + assert_matches!(item.ty, Ty::Ref { .. }); + } } diff --git a/sway-parse/src/keywords.rs b/sway-parse/src/keywords.rs index f75b08072ad..cd5bdb25a61 100644 --- a/sway-parse/src/keywords.rs +++ b/sway-parse/src/keywords.rs @@ -65,7 +65,6 @@ keyword_impls! { WhileToken, WhereToken, RefToken, - DerefToken, TrueToken, FalseToken, BreakToken, @@ -185,7 +184,6 @@ pub const RESERVED_KEYWORDS: phf::Set<&'static str> = phf::phf_set! { "while", "where", "ref", - "deref", "true", "false", "break", diff --git a/sway-parse/src/ty/mod.rs b/sway-parse/src/ty/mod.rs index 18bfc44195c..68a17f68153 100644 --- a/sway-parse/src/ty/mod.rs +++ b/sway-parse/src/ty/mod.rs @@ -9,7 +9,7 @@ use sway_types::{ast::Delimiter, Ident}; impl Parse for Ty { fn parse(parser: &mut Parser) -> ParseResult { // parse parens carefully, such that only patterns of (ty) are parsed as ty, - // and patterns of (ty,) are parsed as one-artity tuples with one element ty + // and patterns of (ty,) are parsed as one-arity tuples with one element ty if let Some((mut parser, span)) = parser.enter_delimited(Delimiter::Parenthesis) { if let Some(_consumed) = parser.check_empty() { return Ok(Ty::Tuple(Parens::new(TyTupleDescriptor::Nil, span))); @@ -60,6 +60,13 @@ impl Parse for Ty { })?; return Ok(Ty::Slice { slice_token, ty }); } + if let Some(ampersand_token) = parser.take() { + let ty = Box::new(parser.parse()?); + return Ok(Ty::Ref { + ampersand_token, + ty, + }); + } if parser.peek::().is_some() || parser.peek::().is_some() || parser.peek::().is_some() @@ -118,4 +125,14 @@ mod tests { ); assert_matches!(item, Ty::Slice { .. }); } + + #[test] + fn parse_ref() { + let item = parse::( + r#" + &T + "#, + ); + assert_matches!(item, Ty::Ref { .. }); + } } diff --git a/swayfmt/src/utils/language/expr/mod.rs b/swayfmt/src/utils/language/expr/mod.rs index c11e7808122..7138a32daf5 100644 --- a/swayfmt/src/utils/language/expr/mod.rs +++ b/swayfmt/src/utils/language/expr/mod.rs @@ -398,12 +398,15 @@ impl Format for Expr { field_span.as_str(), )?; } - Self::Ref { ref_token, expr } => { - write!(formatted_code, "{} ", ref_token.span().as_str())?; + Self::Ref { + ampersand_token, + expr, + } => { + write!(formatted_code, "{}", ampersand_token.span().as_str())?; expr.format(formatted_code, formatter)?; } - Self::Deref { deref_token, expr } => { - write!(formatted_code, "{} ", deref_token.span().as_str())?; + Self::Deref { star_token, expr } => { + write!(formatted_code, "{}", star_token.span().as_str())?; expr.format(formatted_code, formatter)?; } Self::Not { bang_token, expr } => { @@ -1063,13 +1066,16 @@ fn expr_leaf_spans(expr: &Expr) -> Vec { collected_spans.push(ByteSpan::from(field_span.clone())); collected_spans } - Expr::Ref { ref_token, expr } => { - let mut collected_spans = vec![ByteSpan::from(ref_token.span())]; + Expr::Ref { + ampersand_token, + expr, + } => { + let mut collected_spans = vec![ByteSpan::from(ampersand_token.span())]; collected_spans.append(&mut expr.leaf_spans()); collected_spans } - Expr::Deref { deref_token, expr } => { - let mut collected_spans = vec![ByteSpan::from(deref_token.span())]; + Expr::Deref { star_token, expr } => { + let mut collected_spans = vec![ByteSpan::from(star_token.span())]; collected_spans.append(&mut expr.leaf_spans()); collected_spans } diff --git a/swayfmt/src/utils/language/ty.rs b/swayfmt/src/utils/language/ty.rs index 6eebb54f275..5913fca0215 100644 --- a/swayfmt/src/utils/language/ty.rs +++ b/swayfmt/src/utils/language/ty.rs @@ -6,7 +6,7 @@ use std::fmt::Write; use sway_ast::{ brackets::SquareBrackets, expr::Expr, - keywords::{PtrToken, SliceToken, StrToken, Token, UnderscoreToken}, + keywords::{AmpersandToken, PtrToken, SliceToken, StrToken, Token, UnderscoreToken}, ty::{Ty, TyArrayDescriptor, TyTupleDescriptor}, }; use sway_types::{ast::Delimiter, Spanned}; @@ -45,6 +45,10 @@ impl Format for Ty { Self::Slice { slice_token, ty } => { format_slice(formatted_code, slice_token.clone(), ty.clone()) } + Self::Ref { + ampersand_token, + ty, + } => format_ref(formatted_code, ampersand_token.clone(), ty.clone()), } } } @@ -115,6 +119,20 @@ fn format_slice( Ok(()) } +fn format_ref( + formatted_code: &mut FormattedCode, + ampersand_token: AmpersandToken, + ty: Box, +) -> Result<(), FormatterError> { + write!( + formatted_code, + "{}{}", + ampersand_token.span().as_str(), + ty.span().as_str() + )?; + Ok(()) +} + impl Format for TyTupleDescriptor { fn format( &self, @@ -172,6 +190,14 @@ impl LeafSpans for Ty { collected_spans.append(&mut ty.leaf_spans()); collected_spans } + Ty::Ref { + ampersand_token, + ty, + } => { + let mut collected_spans = vec![ByteSpan::from(ampersand_token.span())]; + collected_spans.append(&mut ty.leaf_spans()); + collected_spans + } } } } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/asm_read_from_uninitialized_reg/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/asm_read_from_uninitialized_reg/src/main.sw index f40f974e218..fba02a0167b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/asm_read_from_uninitialized_reg/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/asm_read_from_uninitialized_reg/src/main.sw @@ -1,23 +1,23 @@ script; fn main() -> u64 { - // Returning an unitialized register is not ok + // Returning an uninitialized register is not ok let _ = asm(r1) { r1: u64 }; - // Reading unitialized register is not ok + // Reading uninitialized register is not ok asm(r2) { sw r2 r2 i0; }; - // Writing before reading unitialized register is ok + // Writing before reading uninitialized register is ok asm(r3) { movi r3 i0; sw r3 r3 i0; }; - // Writing before returning unitialized register is ok + // Writing before returning uninitialized register is ok let _ = asm(r4) { movi r4 i0; r4: u64 diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/asm_read_from_uninitialized_reg/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/asm_read_from_uninitialized_reg/test.toml index 7eb4780db3a..87ae815f09d 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/asm_read_from_uninitialized_reg/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/asm_read_from_uninitialized_reg/test.toml @@ -1,9 +1,9 @@ category = "fail" -# check: $()Returning an unitialized register is not ok +# check: $()Returning an uninitialized register is not ok # nextln: $()let _ = asm(r1) -# nextln: $()Unitialized register is being read before being written +# nextln: $()Uninitialized register is being read before being written -# check: $()Reading unitialized register is not ok +# check: $()Reading uninitialized register is not ok # nextln: $()asm(r2) -# nextln: $()Unitialized register is being read before being written +# nextln: $()Uninitialized register is being read before being written diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/ref_and_deref_expressions/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/ref_and_deref_expressions/src/main.sw index 01eacb564ff..aaae45380f7 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/ref_and_deref_expressions/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/ref_and_deref_expressions/src/main.sw @@ -6,7 +6,7 @@ abi MyContract { impl MyContract for Contract { fn test_function() -> bool { - foo(ref Vec::new()); + foo(ref Vec::new()); // TODO-IG: Improve message for these cases (during the implementation of passing references to functions). true } } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/ref_and_deref_expressions/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/ref_and_deref_expressions/test.toml index db7778e4dd9..a512051afe0 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/ref_and_deref_expressions/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_fail/ref_and_deref_expressions/test.toml @@ -3,4 +3,4 @@ category = "fail" # check: $()error # nextln: ref_and_deref_expressions/src/main.sw:9:13 # check: $()foo(ref Vec::new()); -# nextln: $()Ref expressions are not supported yet. +# nextln: $()Identifiers cannot be a reserved keyword. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/Forc.lock new file mode 100644 index 00000000000..5a6458d4404 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-8197477F1603ADA7" + +[[package]] +name = "dereferencing_control_flow_expressions" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-8197477F1603ADA7" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/Forc.toml new file mode 100644 index 00000000000..661555058f2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +license = "Apache-2.0" +name = "dereferencing_control_flow_expressions" +entry = "main.sw" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/src/main.sw new file mode 100644 index 00000000000..e11c94f1c4d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/src/main.sw @@ -0,0 +1,114 @@ +script; + +fn test_dereferencing_break_return_unit() { + while true { + *&break; + assert(false); + } +} + +fn test_double_dereferencing_break_return_unit() { + while true { + ** & &break; + assert(false); + } +} + +fn test_dereferencing_break() -> u64 { + while true { + *&break; + assert(false); + } + + 42 +} + +fn test_double_dereferencing_break() -> u64 { + while true { + ** & &break; + assert(false); + } + + 42 +} + +fn test_dereferencing_continue() -> u64 { + let mut i = 0; + while i < 42 { + i = i + 1; + *&continue; + assert(false); + } + + i +} + +fn test_double_dereferencing_continue() -> u64 { + let mut i = 0; + while i < 42 { + i = i + 1; + ** & &continue; + assert(false); + } + + i +} + +fn test_dereferencing_return_return_unit() { + while true { + *&return; + assert(false); + } + + assert(false); +} + +fn test_double_dereferencing_return_return_unit() { + while true { + ** & &return; + assert(false); + } + + assert(false); +} + +fn test_dereferencing_return() -> u64 { + while true { + *&return 42; + assert(false); + } + + assert(false); + + 43 +} + +fn test_double_dereferencing_return() -> u64 { + while true { + ** & &return 42; + assert(false); + } + + assert(false); + + 43 +} + +fn main() -> u64 { + test_dereferencing_break_return_unit(); + test_double_dereferencing_break_return_unit(); + + assert(42 == test_dereferencing_break()); + assert(42 == test_double_dereferencing_break()); + + assert(42 == test_dereferencing_continue()); + assert(42 == test_double_dereferencing_continue()); + + test_dereferencing_return_return_unit(); + test_double_dereferencing_return_return_unit(); + + assert(42 == test_dereferencing_return()); + assert(42 == test_double_dereferencing_return()); + + 42 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/test.toml new file mode 100644 index 00000000000..9f9fb9da57a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 20 \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/Forc.lock new file mode 100644 index 00000000000..217be49aadf --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-6321F0945AEE50CC" + +[[package]] +name = "dereferencing_operator_star" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-6321F0945AEE50CC" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/Forc.toml new file mode 100644 index 00000000000..c1c11cfd16f --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "dereferencing_operator_star" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/src/impls.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/src/impls.sw new file mode 100644 index 00000000000..dad85dd3649 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/src/impls.sw @@ -0,0 +1,258 @@ +library; + +use core::ops::Eq; +use std::bytes_conversions::u256::*; +use std::bytes_conversions::b256::*; + +pub trait TestInstance { + fn new() -> Self; + fn different() -> Self; +} + +impl TestInstance for bool { + fn new() -> Self { + true + } + fn different() -> Self { + false + } +} + +impl TestInstance for u8 { + fn new() -> Self { + 123 + } + fn different() -> Self { + 223 + } +} + +impl TestInstance for u16 { + fn new() -> Self { + 1234 + } + fn different() -> Self { + 4321 + } +} + +impl TestInstance for u32 { + fn new() -> Self { + 12345 + } + fn different() -> Self { + 54321 + } +} + +impl TestInstance for u64 { + fn new() -> Self { + 123456 + } + fn different() -> Self { + 654321 + } +} + +impl TestInstance for u256 { + fn new() -> Self { + 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20u256 + } + fn different() -> Self { + 0x0203040405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1f1a20u256 + } +} + +impl TestInstance for str { + fn new() -> Self { + "1a2B3c" + } + fn different() -> Self { + "3A2b1C" + } +} + +impl Eq for str[6] { + fn eq(self, other: Self) -> bool { + let mut i = 0; + while i < 6 { + let ptr_self = __addr_of(self).add::(i); + let ptr_other = __addr_of(other).add::(i); + + if ptr_self.read::() != ptr_other.read::() { + return false; + } + + i = i + 1; + }; + + true + } +} + +impl TestInstance for str[6] { + fn new() -> Self { + __to_str_array("1a2B3c") + } + fn different() -> Self { + __to_str_array("3A2b1C") + } +} + +impl Eq for [u64;2] { + fn eq(self, other: Self) -> bool { + self[0] == other[0] && self[1] == other[1] + } +} + +impl TestInstance for [u64;2] { + fn new() -> Self { + [123456, 654321] + } + fn different() -> Self { + [654321, 123456] + } +} + +pub struct Struct { + x: u64, +} + +impl Eq for Struct { + fn eq(self, other: Self) -> bool { + self.x == other.x + } +} + +impl TestInstance for Struct { + fn new() -> Self { + Self { x: 98765 } + } + fn different() -> Self { + Self { x: 56789 } + } +} + +pub struct EmptyStruct { } + +impl Eq for EmptyStruct { + fn eq(self, other: Self) -> bool { + true + } +} + +impl TestInstance for EmptyStruct { + fn new() -> Self { + EmptyStruct { } + } + fn different() -> Self { + EmptyStruct { } + } +} + +pub enum Enum { + A: u64, +} + +impl Eq for Enum { + fn eq(self, other: Self) -> bool { + match (self, other) { + (Enum::A(l), Enum::A(r)) => l == r, + } + } +} + +impl TestInstance for Enum { + fn new() -> Self { + Self::A(123456) + } + fn different() -> Self { + Self::A(654321) + } +} + +impl Eq for (u8, u32) { + fn eq(self, other: Self) -> bool { + self.0 == other.0 && self.1 == other.1 + } +} + +impl TestInstance for (u8, u32) { + fn new() -> Self { + (123, 12345) + } + fn different() -> Self { + (223, 54321) + } +} + +impl TestInstance for b256 { + fn new() -> Self { + 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20 + } + fn different() -> Self { + 0x0202020405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1f1a20 + } +} + +impl TestInstance for raw_ptr { + fn new() -> Self { + let null_ptr = asm() { zero: raw_ptr }; + + null_ptr.add::(42) + } + fn different() -> Self { + let null_ptr = asm() { zero: raw_ptr }; + + null_ptr.add::(42*2) + } +} + +impl TestInstance for raw_slice { + fn new() -> Self { + let null_ptr = asm() { zero: raw_ptr }; + + std::raw_slice::from_parts::(null_ptr, 42) + } + fn different() -> Self { + let null_ptr = asm() { zero: raw_ptr }; + + std::raw_slice::from_parts::(null_ptr, 42*2) + } +} + +impl Eq for raw_slice { + fn eq(self, other: Self) -> bool { + self.ptr() == other.ptr() && self.number_of_bytes() == other.number_of_bytes() + } +} + +impl TestInstance for () { + fn new() -> Self { + () + } + fn different() -> Self { + () + } +} + +impl Eq for () { + fn eq(self, other: Self) -> bool { + true + } +} + +impl TestInstance for [u64;0] { + fn new() -> Self { + [] + } + fn different() -> Self { + [] + } +} + +impl Eq for [u64;0] { + fn eq(self, other: Self) -> bool { + true + } +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/src/main.sw new file mode 100644 index 00000000000..5c8c8eb593a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/src/main.sw @@ -0,0 +1,443 @@ +script; + +mod impls; +use impls::*; +use core::ops::Eq; + +#[inline(always)] +fn dereference() + where T: TestInstance + Eq +{ + let mut x = T::new(); + let r_x = &x; + let r_r_x = &r_x; + let r_r_r_x = &r_r_x; + + assert(*r_x == x); + assert(**r_r_x == x); + assert(***r_r_r_x == x); + + let r_x_ptr = asm(r: r_x) { r: raw_ptr }; + let r_r_x_ptr = asm(r: r_r_x) { r: raw_ptr }; + + let x_d: T = *r_x; + let r_x_d: &T = *r_r_x; + let r_r_x_d: & &T = *r_r_r_x; + + let r_x_d_ptr = asm(r: r_x_d) { r: raw_ptr }; + let r_r_x_d_ptr = asm(r: r_r_x_d) { r: raw_ptr }; + + assert(x_d == x); + assert(r_x_d_ptr == r_x_ptr); + assert(r_r_x_d_ptr == r_r_x_ptr); + + x = T::different(); + + assert(*r_x == x); + assert(**r_r_x == x); + assert(***r_r_r_x == x); +} + +#[inline(never)] +fn dereference_not_inlined() + where T: TestInstance + Eq +{ + dereference::() +} + +#[inline(always)] +fn dereference_array() + where T: TestInstance + Eq +{ + let mut x = [T::new(), T::new()]; + let r_x = &x; + let r_r_x = &r_x; + let r_r_r_x = &r_r_x; + + assert((*r_x)[0] == T::new()); + assert((*r_x)[1] == T::new()); + + assert((**r_r_x)[0] == T::new()); + assert((**r_r_x)[1] == T::new()); + + assert((***r_r_r_x)[0] == T::new()); + assert((***r_r_r_x)[1] == T::new()); + + x[0] = T::different(); + x[1] = T::different(); + + assert((*r_x)[0] == T::different()); + assert((*r_x)[1] == T::different()); + + assert((**r_r_x)[0] == T::different()); + assert((**r_r_x)[1] == T::different()); + + assert((***r_r_r_x)[0] == T::different()); + assert((***r_r_r_x)[1] == T::different()); +} + +#[inline(never)] +fn dereference_array_not_inlined() + where T: TestInstance + Eq +{ + dereference_array::() +} + +#[inline(always)] +fn dereference_tuple() + where T: TestInstance + Eq +{ + let mut x = (T::new(), T::new()); + let r_x = &x; + let r_r_x = &r_x; + let r_r_r_x = &r_r_x; + + assert((*r_x).0 == T::new()); + assert((*r_x).1 == T::new()); + + assert((**r_r_x).0 == T::new()); + assert((**r_r_x).1 == T::new()); + + assert((***r_r_r_x).0 == T::new()); + assert((***r_r_r_x).1 == T::new()); + + x.0 = T::different(); + x.1 = T::different(); + + assert((*r_x).0 == T::different()); + assert((*r_x).1 == T::different()); + + assert((**r_r_x).0 == T::different()); + assert((**r_r_x).1 == T::different()); + + assert((***r_r_r_x).0 == T::different()); + assert((***r_r_r_x).1 == T::different()); +} + +#[inline(never)] +fn dereference_tuple_not_inlined() + where T: TestInstance + Eq +{ + dereference_tuple::() +} + +struct S + where T: TestInstance + Eq +{ + x: T, + y: T +} + +#[inline(always)] +fn dereference_struct() + where T: TestInstance + Eq +{ + let mut x = S { x: T::new(), y: T::new() }; + let r_x = &x; + let r_r_x = &r_x; + let r_r_r_x = &r_r_x; + + assert((*r_x).x == T::new()); + assert((*r_x).y == T::new()); + + assert((**r_r_x).x == T::new()); + assert((**r_r_x).y == T::new()); + + assert((***r_r_r_x).x == T::new()); + assert((***r_r_r_x).y == T::new()); + + x.x = T::different(); + x.y = T::different(); + + assert((*r_x).x == T::different()); + assert((*r_x).y == T::different()); + + assert((**r_r_x).x == T::different()); + assert((**r_r_x).y == T::different()); + + assert((***r_r_r_x).x == T::different()); + assert((***r_r_r_x).y == T::different()); +} + +#[inline(never)] +fn dereference_struct_not_inlined() + where T: TestInstance + Eq +{ + dereference_struct::() +} + +enum E + where T: TestInstance + Eq +{ + A: T, + B: T, +} + +#[inline(always)] +fn dereference_enum() + where T: TestInstance + Eq +{ + let mut x = E::A(T::new()); + let r_x = &x; + let r_r_x = &r_x; + let r_r_r_x = &r_r_x; + + // TODO-IG: Uncomment the version with (t) once this issue for match expression is resolved: + // error: Internal compiler error: Unable to resolve variable 't'. + + match *r_x { + E::A(_) => assert(true), + //E::A(t) => assert(t == T::new()), + _ => assert(false), + }; + + match **r_r_x { + E::A(_) => assert(true), + //E::A(t) => assert(t == T::new()), + _ => assert(false), + }; + + match ***r_r_r_x { + E::A(_) => assert(true), + //E::A(t) => assert(t == T::new()), + _ => assert(false), + }; + + x = E::B(T::different()); + + match *r_x { + E::B(_) => assert(true), + //E::B(t) => assert(t == T::different()), + _ => assert(false), + }; + + match **r_r_x { + E::B(_) => assert(true), + //E::B(t) => assert(t == T::different()), + _ => assert(false), + }; + + match ***r_r_r_x { + E::B(_) => assert(true), + //E::B(t) => assert(t == T::different()), + _ => assert(false), + }; +} + +#[inline(never)] +fn dereference_enum_not_inlined() + where T: TestInstance + Eq +{ + dereference_enum::() +} + +#[inline(never)] +fn test_all_inlined() { + dereference::<()>(); + dereference::(); + dereference::(); + dereference::(); + dereference::(); + dereference::(); + dereference::(); + dereference::<[u64;2]>(); + dereference::<[u64;0]>(); + dereference::(); + dereference::(); + dereference::(); + dereference::(); + dereference::(); + dereference::<(u8, u32)>(); + dereference::(); + dereference::(); + dereference::(); + + dereference_array::<()>(); + dereference_array::(); + dereference_array::(); + dereference_array::(); + dereference_array::(); + dereference_array::(); + // TODO-IG: Uncomment once this issue is solved: https://github.com/FuelLabs/sway/issues/5377 + // thread 'main' panicked at sway-ir/src/optimize/sroa.rs:174:25: + // assertion failed: ty.is_aggregate(context) + //dereference_array::(); + dereference_array::<[u64;2]>(); + dereference_array::<[u64;0]>(); + dereference_array::(); + dereference_array::(); + dereference_array::(); + dereference_array::(); + dereference_array::(); + dereference_array::<(u8, u32)>(); + dereference_array::(); + dereference_array::(); + dereference_array::(); + + dereference_tuple::<()>(); + dereference_tuple::(); + dereference_tuple::(); + dereference_tuple::(); + dereference_tuple::(); + dereference_tuple::(); + // TODO-IG: Uncomment once this issue is solved: https://github.com/FuelLabs/sway/issues/5377 + //dereference_tuple::(); + dereference_tuple::<[u64;2]>(); + dereference_tuple::<[u64;0]>(); + dereference_tuple::(); + dereference_tuple::(); + dereference_tuple::(); + dereference_tuple::(); + dereference_tuple::(); + dereference_tuple::<(u8, u32)>(); + dereference_tuple::(); + dereference_tuple::(); + dereference_tuple::(); + + dereference_struct::<()>(); + dereference_struct::(); + dereference_struct::(); + dereference_struct::(); + dereference_struct::(); + dereference_struct::(); + // TODO-IG: Uncomment once this issue is solved: https://github.com/FuelLabs/sway/issues/5377 + //dereference_struct::(); + dereference_struct::<[u64;2]>(); + dereference_struct::<[u64;0]>(); + dereference_struct::(); + dereference_struct::(); + dereference_struct::(); + dereference_struct::(); + dereference_struct::(); + dereference_struct::<(u8, u32)>(); + dereference_struct::(); + dereference_struct::(); + dereference_struct::(); + + dereference_enum::<()>(); + dereference_enum::(); + dereference_enum::(); + dereference_enum::(); + dereference_enum::(); + dereference_enum::(); + dereference_enum::(); + dereference_enum::<[u64;2]>(); + dereference_enum::<[u64;0]>(); + dereference_enum::(); + dereference_enum::(); + dereference_enum::(); + dereference_enum::(); + dereference_enum::(); + dereference_enum::<(u8, u32)>(); + dereference_enum::(); + dereference_enum::(); + dereference_enum::(); +} + +#[inline(never)] +fn test_not_inlined() { + dereference_not_inlined::<()>(); + dereference_not_inlined::(); + dereference_not_inlined::(); + dereference_not_inlined::(); + dereference_not_inlined::(); + dereference_not_inlined::(); + dereference_not_inlined::(); + dereference_not_inlined::<[u64;2]>(); + dereference_not_inlined::<[u64;0]>(); + dereference_not_inlined::(); + dereference_not_inlined::(); + dereference_not_inlined::(); + dereference_not_inlined::(); + dereference_not_inlined::(); + dereference_not_inlined::<(u8, u32)>(); + dereference_not_inlined::(); + dereference_not_inlined::(); + dereference_not_inlined::(); + + dereference_array_not_inlined::<()>(); + dereference_array_not_inlined::(); + dereference_array_not_inlined::(); + dereference_array_not_inlined::(); + dereference_array_not_inlined::(); + dereference_array_not_inlined::(); + // TODO-IG: Uncomment once this issue is solved: https://github.com/FuelLabs/sway/issues/5377 + //dereference_array_not_inlined::(); + dereference_array_not_inlined::<[u64;2]>(); + dereference_array_not_inlined::<[u64;0]>(); + dereference_array_not_inlined::(); + dereference_array_not_inlined::(); + dereference_array_not_inlined::(); + dereference_array_not_inlined::(); + dereference_array_not_inlined::(); + dereference_array_not_inlined::<(u8, u32)>(); + dereference_array_not_inlined::(); + dereference_array_not_inlined::(); + dereference_array_not_inlined::(); + + dereference_tuple_not_inlined::<()>(); + dereference_tuple_not_inlined::(); + dereference_tuple_not_inlined::(); + dereference_tuple_not_inlined::(); + dereference_tuple_not_inlined::(); + dereference_tuple_not_inlined::(); + // TODO-IG: Uncomment once this issue is solved: https://github.com/FuelLabs/sway/issues/5377 + //dereference_tuple_not_inlined::(); + dereference_tuple_not_inlined::<[u64;2]>(); + dereference_tuple_not_inlined::<[u64;0]>(); + dereference_tuple_not_inlined::(); + dereference_tuple_not_inlined::(); + dereference_tuple_not_inlined::(); + dereference_tuple_not_inlined::(); + dereference_tuple_not_inlined::(); + dereference_tuple_not_inlined::<(u8, u32)>(); + dereference_tuple_not_inlined::(); + dereference_tuple_not_inlined::(); + dereference_tuple_not_inlined::(); + + dereference_struct_not_inlined::<()>(); + dereference_struct_not_inlined::(); + dereference_struct_not_inlined::(); + dereference_struct_not_inlined::(); + dereference_struct_not_inlined::(); + dereference_struct_not_inlined::(); + // TODO-IG: Uncomment once this issue is solved: https://github.com/FuelLabs/sway/issues/5377 + //dereference_struct_not_inlined::(); + dereference_struct_not_inlined::<[u64;2]>(); + dereference_struct_not_inlined::<[u64;0]>(); + dereference_struct_not_inlined::(); + dereference_struct_not_inlined::(); + dereference_struct_not_inlined::(); + dereference_struct_not_inlined::(); + dereference_struct_not_inlined::(); + dereference_struct_not_inlined::<(u8, u32)>(); + dereference_struct_not_inlined::(); + dereference_struct_not_inlined::(); + dereference_struct_not_inlined::(); + + dereference_enum_not_inlined::<()>(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::<[u64;2]>(); + dereference_enum_not_inlined::<[u64;0]>(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::<(u8, u32)>(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::(); + dereference_enum_not_inlined::(); +} + +fn main() -> u64 { + test_all_inlined(); + test_not_inlined(); + + 42 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/test.toml new file mode 100644 index 00000000000..a19267f94a8 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 9 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/Forc.lock new file mode 100644 index 00000000000..3f67f01ae08 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-1F7B33F0B2B16AF4" + +[[package]] +name = "impl_reference_types" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-1F7B33F0B2B16AF4" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/Forc.toml new file mode 100644 index 00000000000..71d74ec4120 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "impl_reference_types" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/src/main.sw new file mode 100644 index 00000000000..e45f18308fc --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/src/main.sw @@ -0,0 +1,154 @@ +script; + +impl &u64 { + fn get_value(self) -> u64 { + let ptr = asm(r: self) { r: raw_ptr }; + + ptr.read::() + } + + fn get_value_deref(self) -> u64 { + *self + } +} + +impl & &u64 { + fn get_value(self) -> u64 { + let ptr = asm(r: self) { r: raw_ptr }; + + ptr.read::().read::() * 2 + } + + fn get_value_deref(self) -> u64 { + // Just to play a bit with the parser while we are here :-) + assert(**self * 2 == 2 * **self); + assert(* * self * 2 == 2 * * * self); + assert(**self*2 == 2* **self); + // ^ This space is needed to disambiguate from `pow`. + + **self * 2 + } +} + +impl &[u64;2] { + fn get_value(self, index: u64) -> u64 { + let ptr = asm(r: self) { r: raw_ptr }; + + ptr.read::<[u64;2]>()[index] + } + + fn get_value_deref(self, index: u64) -> u64 { + (*self)[index] + } +} + +impl & &[u64;2] { + fn get_value(self, index: u64) -> u64 { + let ptr = asm(r: self) { r: raw_ptr }; + + ptr.read::().read::<[u64;2]>()[index] * 2 + } + + fn get_value_deref(self, index: u64) -> u64 { + (**self)[index] * 2 + } +} + +trait Trait { + fn trait_function() -> u64; + fn trait_method(self) -> u64; + fn trait_method_deref(self) -> u64; +} + +impl Trait for &u64 { + fn trait_function() -> u64 { + 64 + } + + fn trait_method(self) -> u64 { + let ptr = asm(r: self) { r: raw_ptr }; + + ptr.read::() + } + + fn trait_method_deref(self) -> u64 { + *self + } +} + +impl Trait for & &u64 { + fn trait_function() -> u64 { + 64 * 2 + } + + fn trait_method(self) -> u64 { + let ptr = asm(r: self) { r: raw_ptr }; + + ptr.read::().read::() * 2 + } + + fn trait_method_deref(self) -> u64 { + **self * 2 + } +} + +type RefToU64 = &u64; +type RefToRefToU64 = & &u64; +type RefToRefToU64Alias = &RefToU64; + +fn main() -> u64 { + let mut x = 123u64; + let r_x = &x; + let r_r_x = & &x; + + assert(r_x.get_value() == x); + assert(r_x.get_value_deref() == x); + assert(r_r_x.get_value() == x * 2); + assert(r_r_x.get_value_deref() == x * 2); + + x = 2 * x; + + assert(r_x.get_value() == x); + assert(r_x.get_value_deref() == x); + assert(r_r_x.get_value() == x * 2); + assert(r_r_x.get_value_deref() == x * 2); + + let mut array = [x, x + 100]; + let r_array = &array; + let r_r_array = & &array; + + assert(r_array.get_value(0) == x); + assert(r_array.get_value_deref(0) == x); + assert(r_array.get_value(1) == x + 100); + assert(r_array.get_value_deref(1) == x + 100); + + assert(r_r_array.get_value(0) == x * 2); + assert(r_r_array.get_value_deref(0) == x * 2); + assert(r_r_array.get_value(1) == (x + 100) * 2); + assert(r_r_array.get_value_deref(1) == (x + 100) * 2); + + x = 2 * x; + array[0] = x; + array[1] = x + 100; + + assert(r_array.get_value(0) == x); + assert(r_array.get_value_deref(0) == x); + assert(r_array.get_value(1) == x + 100); + assert(r_array.get_value_deref(1) == x + 100); + + assert(r_r_array.get_value(0) == x * 2); + assert(r_r_array.get_value_deref(0) == x * 2); + assert(r_r_array.get_value(1) == (x + 100) * 2); + assert(r_r_array.get_value_deref(1) == (x + 100) * 2); + + assert(r_x.trait_method() == x); + assert(r_x.trait_method_deref() == x); + assert(RefToU64::trait_function() == 64); + + assert(r_r_x.trait_method() == x * 2); + assert(r_r_x.trait_method_deref() == x * 2); + assert(RefToRefToU64::trait_function() == 64 * 2); + assert(RefToRefToU64Alias::trait_function() == 64 * 2); + + 42 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/test.toml new file mode 100644 index 00000000000..90de30d80ec --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/impl_reference_types/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 0 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/Forc.lock new file mode 100644 index 00000000000..06a225a5220 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-3010732701006D5E" + +[[package]] +name = "mutability_of_references" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-3010732701006D5E" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/Forc.toml new file mode 100644 index 00000000000..b9b0b0f5e85 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "mutability_of_references" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/src/main.sw new file mode 100644 index 00000000000..5dd6495a49f --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/src/main.sw @@ -0,0 +1,35 @@ +script; + +fn main() -> u64 { + let r = &1u8; + let mut m_r = &1u8; + + let r_ptr = asm(r: r) { r: raw_ptr }; + let m_r_ptr_01 = asm(r: m_r) { r: raw_ptr }; + + assert(r_ptr != m_r_ptr_01); + + assert(*r == *m_r); + + m_r = &(1u8 + 1); + + let m_r_ptr_02 = asm(r: m_r) { r: raw_ptr }; + + assert(r_ptr != m_r_ptr_01); + assert(r_ptr != m_r_ptr_02); + assert(m_r_ptr_01 != m_r_ptr_02); + + assert(*r != *m_r); + + m_r = r; + + let m_r_ptr_03 = asm(r: m_r) { r: raw_ptr }; + + assert(r_ptr != m_r_ptr_01); + assert(r_ptr != m_r_ptr_02); + assert(r_ptr == m_r_ptr_03); + + assert(*r == *m_r); + + 42 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/test.toml new file mode 100644 index 00000000000..90de30d80ec --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 0 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/Forc.lock new file mode 100644 index 00000000000..84d9f6f190a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-F6AA645E4A741D0E" + +[[package]] +name = "passing_and_returning_references_to_and_from_functions" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-F6AA645E4A741D0E" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/Forc.toml new file mode 100644 index 00000000000..1381c0e7470 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "passing_and_returning_references_to_and_from_functions" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/src/main.sw new file mode 100644 index 00000000000..885f85118af --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/src/main.sw @@ -0,0 +1,205 @@ +script; + +use core::ops::Eq; + +struct S { + x: u8, +} + +impl S { + fn new() -> Self { + Self { x: 0 } + } + + fn use_me(self) { + poke(self.x); + } +} + +impl Eq for S { + fn eq(self, other: Self) -> bool { + self.x == other.x + } +} + +#[inline(always)] +fn reference_to_copy_type() { + let x = 123u8; + let r_x = &x; + + let ptr = asm(r: &x) { r: raw_ptr }; + + let r_ret = copy_type_ref(&x, x, ptr); + let r_ret_ptr = asm(r: r_ret) { r: raw_ptr }; + assert(r_ret_ptr == ptr); + + assert(*r_ret == *r_x); + + let r_ret = copy_type_ref(r_x, x, ptr); + let r_ret_ptr = asm(r: r_ret) { r: raw_ptr }; + assert(r_ret_ptr == ptr); + + assert(*r_ret == *r_x); +} + +#[inline(never)] +fn reference_to_copy_type_not_inlined() { + reference_to_copy_type() +} + +fn copy_type_ref(r: &u8, v: u8, ptr: raw_ptr) -> &u8 { + let r_ptr = asm(r: r) { r: raw_ptr }; + + assert(r_ptr == ptr); + assert(r_ptr.read::() == v); + + assert(*r == v); + + r +} + +#[inline(always)] +fn reference_to_aggregate() { + let s = S { x: 123u8 }; + let r_s = &s; + + let ptr = asm(r: &s) { r: raw_ptr }; + assert(ptr == __addr_of(s)); + + let r_ret = aggregate_ref(&s, s, ptr); + let r_ret_ptr = asm(r: r_ret) { r: raw_ptr }; + assert(r_ret_ptr == ptr); + + assert(*r_ret == *r_s); + + let r_ret = aggregate_ref(r_s, s, ptr); + let r_ret_ptr = asm(r: r_ret) { r: raw_ptr }; + assert(r_ret_ptr == ptr); + + assert(*r_ret == *r_s); +} + +#[inline(never)] +fn reference_to_aggregate_not_inlined() { + reference_to_aggregate() +} + +fn aggregate_ref(r: &S, v: S, ptr: raw_ptr) -> &S { + let r_ptr = asm(r: r) { r: raw_ptr }; + + assert(r_ptr == ptr); + assert(r_ptr.read::() == v); + + assert(*r == v); + + r +} + +impl Eq for [u64;2] { + fn eq(self, other: Self) -> bool { + self[0] == other[0] && self[1] == other[1] + } +} + +struct EmptyStruct { } + +impl Eq for EmptyStruct { + fn eq(self, other: Self) -> bool { + true + } +} + +enum E { + A: u8, +} + +impl Eq for E { + fn eq(self, other: Self) -> bool { + match (self, other) { + (E::A(r), E::A(l)) => r == l, + } + } +} + +#[inline(always)] +fn reference_to_generic() { + // TODO-IG: Uncomment once referencing copy type function parameters is implemented. + //reference_to_generic_test(123u8); + //reference_to_generic_test(123u64); + //reference_to_generic_test(true); + + //let s = S { x: 0 }; + //let ptr_s = __addr_of(s); + + //reference_to_generic_test(ptr_s); + + reference_to_generic_test(S { x: 123u8 }); + reference_to_generic_test(EmptyStruct { }); + reference_to_generic_test([123u64, 123u64]); + reference_to_generic_test(E::A(123u8)); +} + +#[inline(always)] +fn reference_to_generic_test(t: T) + where T: Eq +{ + let r_t = &t; + + let ptr = asm(r: &t) { r: raw_ptr }; + + let r_ret = generic_ref(&t, t, ptr); + let r_ret_ptr = asm(r: r_ret) { r: raw_ptr }; + assert(r_ret_ptr == ptr); + + assert(*r_ret == *r_t); + + let r_ret = generic_ref(r_t, t, ptr); + let r_ret_ptr = asm(r: r_ret) { r: raw_ptr }; + assert(r_ret_ptr == ptr); + + assert(*r_ret == *r_t); +} + +#[inline(never)] +fn reference_to_generic_not_inlined() { + reference_to_generic() +} + +fn generic_ref(r: &T, v: T, ptr: raw_ptr) -> &T + where T: Eq +{ + let r_ptr = asm(r: r) { r: raw_ptr }; + + assert(r_ptr == ptr); + assert(r_ptr.read::() == v); + + assert(*r == v); + + r +} + +#[inline(never)] +fn test_all_inlined() { + reference_to_copy_type(); + reference_to_aggregate(); + reference_to_generic(); +} + +#[inline(never)] +fn test_not_inlined() { + reference_to_copy_type_not_inlined(); + reference_to_aggregate_not_inlined(); + reference_to_generic_not_inlined(); +} + +fn main() -> u64 { + test_all_inlined(); + test_not_inlined(); + + S::new().use_me(); + + 42 +} + +#[inline(never)] +fn poke(_x: T) { } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/test.toml new file mode 100644 index 00000000000..90de30d80ec --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/passing_and_returning_references_to_and_from_functions/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 0 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/Forc.lock new file mode 100644 index 00000000000..9b20e6e12ca --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-F7E46146DAFCB544" + +[[package]] +name = "references_and_generics" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-F7E46146DAFCB544" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/Forc.toml new file mode 100644 index 00000000000..bb643ba561f --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "references_and_generics" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/src/main.sw new file mode 100644 index 00000000000..ee3785da3ee --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/src/main.sw @@ -0,0 +1,69 @@ +script; + +use core::ops::Eq; + +struct A { + x: u64, +} + +impl Eq for A { + fn eq(self, other: Self) -> bool { + self.x == other.x + } +} + +struct S where T: Eq +{ + r_t: &T, + r_r_t: & &T, +} + +impl Eq for S where T: Eq { + fn eq(self, other: Self) -> bool { + // Original implementation, before we had dereferencing. + // Let's keep it for more paranoid coverage :-) + let self_r_t_ptr = asm(r: self.r_t) { r: raw_ptr }; + let self_r_r_t_ptr = asm(r: self.r_r_t) { r: raw_ptr }; + + let other_r_t_ptr = asm(r: other.r_t) { r: raw_ptr }; + let other_r_r_t_ptr = asm(r: other.r_r_t) { r: raw_ptr }; + + // And use the opportunity to assert dereferencing ;-) + assert(self_r_t_ptr.read::() == *self.r_t); + assert(other_r_t_ptr.read::() == *other.r_t); + assert(self_r_r_t_ptr.read::().read::() == **self.r_r_t); + assert(other_r_r_t_ptr.read::().read::() == **other.r_r_t); + + self_r_t_ptr.read::() == other_r_t_ptr.read::() + && + self_r_r_t_ptr.read::().read::() == other_r_r_t_ptr.read::().read::() + } +} + +fn test(s: S, v: T) where T: Eq { + let s_r_t_ptr = asm(r: s.r_t) { r: raw_ptr }; + let s_r_r_t_ptr = asm(r: s.r_r_t) { r: raw_ptr }; + + assert(s_r_t_ptr.read::() == v); + assert(s_r_r_t_ptr.read::().read::() == v); + + assert(*s.r_t == v); + assert(**s.r_r_t == v); +} + +fn main() -> u64 { + let x = 123u8; + + let s_x = S { r_t: &x, r_r_t: & &x }; + test(s_x, x); + + let s_s_x = S { r_t: &s_x, r_r_t: & &s_x }; + test(s_s_x, s_x); + + let a = A { x: 321 }; + + let s_a = S { r_t: &a, r_r_t: & &a }; + test(s_a, a); + + 42 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/test.toml new file mode 100644 index 00000000000..90de30d80ec --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_generics/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 0 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/Forc.lock new file mode 100644 index 00000000000..2f4f07b13bd --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-C20A55B9AF89FB67" + +[[package]] +name = "references_and_type_aliases" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-C20A55B9AF89FB67" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/Forc.toml new file mode 100644 index 00000000000..ec9da8429d6 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "references_and_type_aliases" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/src/main.sw new file mode 100644 index 00000000000..90ed2142fe0 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/src/main.sw @@ -0,0 +1,35 @@ +script; + +type RefToU64 = &u64; +// TODO-IG: Once https://github.com/FuelLabs/sway/issues/5401 is solved use the line below. +type RefToTupleOfRefs = &(&u64, &u64); +//type RefToTupleOfRefs = &(&u64, RefToU64); + +fn references_and_type_aliases() { + let r: RefToU64 = &123; + let t: RefToTupleOfRefs = &(r, r); + + let ret: &u64 = passing_and_returning_ref_type_aliases(t); + + let ret_ptr = asm(r: ret) { r: raw_ptr }; + + assert(ret_ptr.read::() == 123); + + assert(*r == 123); +} + +fn passing_and_returning_ref_type_aliases(x: RefToTupleOfRefs) -> RefToU64 { + let x: &(&u64, &u64) = x; + + let ptr = asm(r: x) { r: raw_ptr }; + + let tuple = ptr.read::<(RefToU64, RefToU64)>(); + + tuple.0 +} + +fn main() -> u64 { + references_and_type_aliases(); + + 42 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/test.toml new file mode 100644 index 00000000000..90de30d80ec --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_and_type_aliases/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 0 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/Forc.lock new file mode 100644 index 00000000000..e981217c622 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-8B7392CF84E0FBF2" + +[[package]] +name = "references_in_aggregates" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-8B7392CF84E0FBF2" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/Forc.toml new file mode 100644 index 00000000000..fb70fe29c89 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "references_in_aggregates" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/src/main.sw new file mode 100644 index 00000000000..667693134b6 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/src/main.sw @@ -0,0 +1,240 @@ +script; + +struct A { + r_u8: &u8, + r_array: &[u64;3], +} + +impl A { + fn new() -> Self { + Self { r_u8: &0, r_array: &[0, 0, 0] } + } + + fn use_me(self) { + poke(self.r_u8); + poke(self.r_array); + } +} + +struct B { + r_a: &A, + r_array: &[&A;3], +} + +impl B { + fn new() -> Self { + let r_a = &A::new(); + Self { r_a: r_a, r_array: &[r_a, r_a, r_a] } + } + + fn use_me(self) { + poke(self.r_a); + poke(self.r_array); + } +} + +#[inline(always)] +fn in_structs() { + assert(__size_of::() == 2 * 8); + assert(__size_of::() == 2 * 8); + + let x = 123u8; + let array: [u64;3] = [111, 222, 333]; + + let a = A { r_u8: &x, r_array: &array }; + let b = B { r_a: &a, r_array: &[&a, &a, &a] }; + + let r_x_ptr = asm(r: &x) { r: raw_ptr }; + let r_array_ptr = asm(r: &array) { r: raw_ptr }; + + let r_a_ptr = asm(r: &a) { r: raw_ptr }; + + let a_r_u8_ptr = asm(r: a.r_u8) { r: raw_ptr }; + let a_r_array_ptr = asm(r: a.r_array) { r: raw_ptr }; + + assert(r_x_ptr == a_r_u8_ptr); + assert(r_array_ptr == a_r_array_ptr); + + assert(*&x == *a.r_u8); + assert((*&array)[0] == (*a.r_array)[0]); + assert((*&array)[1] == (*a.r_array)[1]); + assert((*&array)[2] == (*a.r_array)[2]); + + let b_r_a_ptr = asm(r: b.r_a) { r: raw_ptr }; + + assert(r_a_ptr == b_r_a_ptr); + + let a_r_u8_ptr_val = a_r_u8_ptr.read::(); + let a_r_array_ptr_val = a_r_array_ptr.read::<[u64;3]>(); + + assert(a_r_u8_ptr_val == x); + assert(a_r_array_ptr_val[0] == array[0]); + assert(a_r_array_ptr_val[1] == array[1]); + assert(a_r_array_ptr_val[2] == array[2]); + + let b_r_a_ptr_val = b_r_a_ptr.read::(); + let a_r_u8_ptr_over_b = asm(r: b_r_a_ptr_val.r_u8) { r: raw_ptr }; + + assert(a_r_u8_ptr_over_b == a_r_u8_ptr); + + assert(*(*b.r_a).r_u8 == *a.r_u8); + assert((*((*(*b.r_array)[0]).r_array))[0] == (*a.r_array)[0]); + assert((*((*(*b.r_array)[0]).r_array))[1] == (*a.r_array)[1]); + assert((*((*(*b.r_array)[0]).r_array))[2] == (*a.r_array)[2]); +} + +#[inline(never)] +fn in_structs_not_inlined() { + in_structs() +} + +enum E { + R_A: &A, + R_B: &B, +} + +#[inline(always)] +fn in_enums() { + assert(__size_of::() == 2 * 8); + + let x = 123u8; + let array: [u64;3] = [111, 222, 333]; + + let a = A { r_u8: &x, r_array: &array }; + let b = B { r_a: &a, r_array: &[&a, &a, &a] }; + + let r_a_ptr = asm(r: &a) { r: raw_ptr }; + let r_b_ptr = asm(r: &b) { r: raw_ptr }; + + let e_r_a = E::R_A(&a); + let e_r_b = E::R_B(&b); + + match e_r_a { + E::R_A(r_a) => { + let local_r_a: &A = r_a; // To proof `r_a` is of type `&A`. + + let local_r_a_ptr = asm(r: local_r_a) { r: raw_ptr }; + + assert(local_r_a_ptr == r_a_ptr); + + assert(*(*local_r_a).r_u8 == *&x); + assert((*(*local_r_a).r_array)[0] == (*&array)[0]); + assert((*(*local_r_a).r_array)[1] == (*&array)[1]); + assert((*(*local_r_a).r_array)[2] == (*&array)[2]); + } + _ => assert(false), + } + + match e_r_b { + E::R_B(r_b) => { + let local_r_b: &B = r_b; // To proof `r_b` is of type `&B`. + + let local_r_b_ptr = asm(r: local_r_b) { r: raw_ptr }; + + assert(local_r_b_ptr == r_b_ptr); + + assert(*(*(*local_r_b).r_a).r_u8 == *&x); + assert((*(*(*(*local_r_b).r_array)[0]).r_array)[0] == (*&array)[0]); + assert((*(*(*(*local_r_b).r_array)[0]).r_array)[1] == (*&array)[1]); + assert((*(*(*(*local_r_b).r_array)[0]).r_array)[2] == (*&array)[2]); + } + _ => assert(false), + } +} + +#[inline(never)] +fn in_enums_not_inlined() { + in_enums() +} + +#[inline(always)] +fn in_arrays() { + let x = 123u8; + let array: [u64;3] = [111, 222, 333]; + + let a = A { r_u8: &x, r_array: &array }; + let b = B { r_a: &a, r_array: &[&a, &a, &a] }; + + let r_b_ptr = asm(r: &b) { r: raw_ptr }; + + let arr = [&b, &b, &b]; + + assert(__size_of_val(arr) == 3 * 8); + + let r_arr_0_ptr = asm(r: arr[0]) { r: raw_ptr }; + let r_arr_1_ptr = asm(r: arr[1]) { r: raw_ptr }; + let r_arr_2_ptr = asm(r: arr[2]) { r: raw_ptr }; + + assert(r_b_ptr == r_arr_0_ptr); + assert(r_b_ptr == r_arr_1_ptr); + assert(r_b_ptr == r_arr_2_ptr); + + assert((*(*((*(*arr[1]).r_array)[2])).r_array)[0] == (*&array)[0]); + assert((*(*((*(*arr[1]).r_array)[2])).r_array)[1] == (*&array)[1]); + assert((*(*((*(*arr[1]).r_array)[2])).r_array)[2] == (*&array)[2]); +} + +#[inline(never)] +fn in_arrays_not_inlined() { + in_arrays() +} + +#[inline(always)] +fn in_tuples() { + let x = 123u8; + let array: [u64;3] = [111, 222, 333]; + + let a = A { r_u8: &x, r_array: &array }; + let b = B { r_a: &a, r_array: &[&a, &a, &a] }; + + let r_b_ptr = asm(r: &b) { r: raw_ptr }; + + let tuple = (&b, &b, &b); + + assert(__size_of_val(tuple) == 3 * 8); + + let r_tuple_0_ptr = asm(r: tuple.0) { r: raw_ptr }; + let r_tuple_1_ptr = asm(r: tuple.1) { r: raw_ptr }; + let r_tuple_2_ptr = asm(r: tuple.2) { r: raw_ptr }; + + assert(r_b_ptr == r_tuple_0_ptr); + assert(r_b_ptr == r_tuple_1_ptr); + assert(r_b_ptr == r_tuple_2_ptr); + + assert((*(*((*(*tuple.1).r_array)[2])).r_array)[0] == (*&array)[0]); + assert((*(*((*(*tuple.1).r_array)[2])).r_array)[1] == (*&array)[1]); + assert((*(*((*(*tuple.1).r_array)[2])).r_array)[2] == (*&array)[2]); +} + +#[inline(never)] +fn in_tuples_not_inlined() { + in_tuples() +} + +#[inline(never)] +fn test_all_inlined() { + in_structs(); + in_enums(); + in_arrays(); + in_tuples(); +} + +#[inline(never)] +fn test_not_inlined() { + in_structs_not_inlined(); + in_enums_not_inlined(); + in_arrays_not_inlined(); + in_tuples_not_inlined(); +} + +fn main() -> u64 { + test_all_inlined(); + test_not_inlined(); + + A::new().use_me(); + B::new().use_me(); + + 42 +} + +fn poke(_x: T) { } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/test.toml new file mode 100644 index 00000000000..90de30d80ec --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_aggregates/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 0 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/Forc.lock new file mode 100644 index 00000000000..2df153535e5 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-54A4EED6869943AB" + +[[package]] +name = "references_in_asm_blocks" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-54A4EED6869943AB" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/Forc.toml new file mode 100644 index 00000000000..28a25ba573d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "references_in_asm_blocks" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/src/main.sw new file mode 100644 index 00000000000..98226442bcb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/src/main.sw @@ -0,0 +1,129 @@ +script; + +struct S { + x: u8, +} + +#[inline(always)] +fn pass_references_to_asm_blocks() { + let x = 123u8; + + let r_x = &x; + + let r_x_ptr_1 = asm(r: &x) { r: raw_ptr }; + let r_x_ptr_2 = asm(r: r_x) { r: raw_ptr }; + + assert(r_x_ptr_1 == r_x_ptr_2); + + let r_x_ptr_1_val = r_x_ptr_1.read::(); + let r_x_ptr_2_val = r_x_ptr_2.read::(); + + assert(r_x_ptr_1_val == 123u8); + assert(r_x_ptr_2_val == 123u8); + + let r_val_ptr_1 = asm(r: &123u8) { r: raw_ptr }; + let r_val_ptr_2 = asm(r: &(100u8 + 23u8)) { r: raw_ptr }; + let r_val_ptr_3 = asm(r: &return_123u8()) { r: raw_ptr }; + + assert(r_x_ptr_1 != r_val_ptr_1); + assert(r_val_ptr_1 != r_val_ptr_2); + assert(r_val_ptr_2 != r_val_ptr_3); + assert(r_val_ptr_3 != r_x_ptr_1); + + let r_val_ptr_1_val = r_val_ptr_1.read::(); + let r_val_ptr_2_val = r_val_ptr_2.read::(); + let r_val_ptr_3_val = r_val_ptr_3.read::(); + + assert(r_val_ptr_1_val == 123u8); + assert(r_val_ptr_2_val == 123u8); + assert(r_val_ptr_3_val == 123u8); +} + +#[inline(never)] +fn pass_references_to_asm_blocks_not_inlined() { + pass_references_to_asm_blocks() +} + +#[inline(never)] +fn return_123u8() -> u8 { + 123 +} + +#[inline(always)] +fn return_references_from_asm_blocks() { + let x = 123u8; + let r_x = &x; + + let r_x_ptr = asm(r: &x) { r: raw_ptr }; + + let r_x_ref_1 = asm(r: &x) { r: &u8 }; + let r_x_ref_2 = asm(r: r_x) { r: &u8 }; + + let r_x_ref_1_ptr = asm(r: r_x_ref_1) { r: raw_ptr }; + let r_x_ref_2_ptr = asm(r: r_x_ref_2) { r: raw_ptr }; + + assert(r_x_ptr == r_x_ref_1_ptr); + assert(r_x_ptr == r_x_ref_2_ptr); + + // ---- + + let s = S { x: 222 }; + let r_s = &s; + + let r_s_ptr = asm(r: &s) { r: raw_ptr }; + + let r_s_ref_1 = asm(r: &s) { r: &S }; + let r_s_ref_2 = asm(r: r_s) { r: &S }; + + let r_s_ref_1_ptr = asm(r: r_s_ref_1) { r: raw_ptr }; + let r_s_ref_2_ptr = asm(r: r_s_ref_2) { r: raw_ptr }; + + assert(r_s_ptr == r_s_ref_1_ptr); + assert(r_s_ptr == r_s_ref_2_ptr); + + let s_x = r_s_ref_1_ptr.read::(); + + assert(s_x == s.x); + + assert((*r_s).x == s.x); + assert((*r_s_ref_1).x == s.x); + assert((*r_s_ref_2).x == s.x); + + // ---- + // Since aggregates are passed by reference we can always + // cast a reference to an aggregate to the aggregate itself. + // Note that the assignments below will make two copies, + // as well ast the two `asm` blocks. + let s_1 = asm(r: &s) { r: S }; + let s_2 = asm(r: r_s) { r: S }; + + assert(s_1.x == s.x); + assert(s_2.x == s.x); + + assert(asm(r: &s) { r: S }.x == s.x); + assert(asm(r: r_s) { r: S }.x == s.x); +} + +#[inline(never)] +fn return_references_from_asm_blocks_not_inlined() { + return_references_from_asm_blocks() +} + +#[inline(never)] +fn test_all_inlined() { + pass_references_to_asm_blocks(); + return_references_from_asm_blocks(); +} + +#[inline(never)] +fn test_not_inlined() { + pass_references_to_asm_blocks_not_inlined(); + return_references_from_asm_blocks_not_inlined(); +} + +fn main() -> u64 { + test_all_inlined(); + test_not_inlined(); + + 42 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/test.toml new file mode 100644 index 00000000000..90de30d80ec --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/references_in_asm_blocks/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 0 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/Forc.lock new file mode 100644 index 00000000000..7ca0d4f25c3 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-6356DA663B6E255D" + +[[package]] +name = "referencing_control_flow_expressions" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-6356DA663B6E255D" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/Forc.toml new file mode 100644 index 00000000000..c12b0e97b20 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +license = "Apache-2.0" +name = "referencing_control_flow_expressions" +entry = "main.sw" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/src/main.sw new file mode 100644 index 00000000000..6ac12696f45 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/src/main.sw @@ -0,0 +1,114 @@ +script; + +fn test_referencing_break_return_unit() { + while true { + &break; + assert(false); + } +} + +fn test_double_referencing_break_return_unit() { + while true { + & &break; + assert(false); + } +} + +fn test_referencing_break() -> u64 { + while true { + &break; + assert(false); + } + + 42 +} + +fn test_double_referencing_break() -> u64 { + while true { + & &break; + assert(false); + } + + 42 +} + +fn test_referencing_continue() -> u64 { + let mut i = 0; + while i < 42 { + i = i + 1; + &continue; + assert(false); + } + + i +} + +fn test_double_referencing_continue() -> u64 { + let mut i = 0; + while i < 42 { + i = i + 1; + & &continue; + assert(false); + } + + i +} + +fn test_referencing_return_return_unit() { + while true { + &return; + assert(false); + } + + assert(false); +} + +fn test_double_referencing_return_return_unit() { + while true { + & &return; + assert(false); + } + + assert(false); +} + +fn test_referencing_return() -> u64 { + while true { + &return 42; + assert(false); + } + + assert(false); + + 43 +} + +fn test_double_referencing_return() -> u64 { + while true { + & &return 42; + assert(false); + } + + assert(false); + + 43 +} + +fn main() -> u64 { + test_referencing_break_return_unit(); + test_double_referencing_break_return_unit(); + + assert(42 == test_referencing_break()); + assert(42 == test_double_referencing_break()); + + assert(42 == test_referencing_continue()); + assert(42 == test_double_referencing_continue()); + + test_referencing_return_return_unit(); + test_double_referencing_return_return_unit(); + + assert(42 == test_referencing_return()); + assert(42 == test_double_referencing_return()); + + 42 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/test.toml new file mode 100644 index 00000000000..9f9fb9da57a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_control_flow_expressions/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 20 \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/Forc.lock new file mode 100644 index 00000000000..f4ccac20028 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-AFEEDD5F5BF46FB3" + +[[package]] +name = "referencing_expressions" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-AFEEDD5F5BF46FB3" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/Forc.toml new file mode 100644 index 00000000000..e3cf9ff36ec --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "referencing_expressions" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/src/main.sw new file mode 100644 index 00000000000..203c63e4b7a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/src/main.sw @@ -0,0 +1,80 @@ +script; + +use core::ops::Eq; + +struct Struct { + x: u64, +} + +impl core::ops::Eq for Struct { + fn eq(self, other: Self) -> bool { + self.x == other.x + } +} + +impl core::ops::Eq for [Struct; 3] { + fn eq(self, other: Self) -> bool { + self[0] == other[0] && self[1] == other[1] && self[2] == other[2] + } +} + +// TODO-IG: Add tests for other expressions that can be referenced and errors for those that cannot. + +#[inline(always)] +fn if_expr(input: u64, left: T, right: T) where T: Eq { + let x = if input > 42 { + left + } else { + right + }; + + let r_x = &x; + let r_val = &if input > 42 { + left + } else { + right + }; + + let r_x_ptr = asm(r: r_x) { r: raw_ptr }; + let r_val_ptr = asm(r: r_val) { r: raw_ptr }; + + assert(r_x_ptr != r_val_ptr); + + let r_x_ptr_val = r_x_ptr.read::(); + let r_x_val_val = r_val_ptr.read::(); + + assert(r_x_ptr_val == x); + assert(r_x_val_val == x); + + assert(*r_x == x); + assert(*r_val == x); +} + +#[inline(never)] +fn if_expr_not_inlined(input: u64, left: T, right: T) where T: Eq { + if_expr(input, left, right) +} + +#[inline(never)] +fn test_all_inlined(input: u64) { + if_expr(input, 123, 321); + if_expr(input, Struct { x: 123 }, Struct { x: 321 }); + if_expr(input, [Struct { x: 123 }, Struct { x: 123 }, Struct { x: 123 }], [Struct { x: 321 }, Struct { x: 321 }, Struct { x: 321 }]); +} + +#[inline(never)] +fn test_not_inlined(input: u64) { + if_expr_not_inlined(input, 123, 321); + if_expr_not_inlined(input, Struct { x: 123 }, Struct { x: 321 }); + if_expr_not_inlined(input, [Struct { x: 123 }, Struct { x: 123 }, Struct { x: 123 }], [Struct { x: 321 }, Struct { x: 321 }, Struct { x: 321 }]); +} + +fn main() -> u64 { + test_all_inlined(42 - 1); + test_all_inlined(42 + 1); + + test_not_inlined(42 - 1); + test_not_inlined(42 + 1); + + 42 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/test.toml new file mode 100644 index 00000000000..90de30d80ec --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_expressions/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 0 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/Forc.lock new file mode 100644 index 00000000000..ea90ede95e3 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-5FDEE1872BB129D5" + +[[package]] +name = "referencing_function_parameters" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-5FDEE1872BB129D5" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/Forc.toml new file mode 100644 index 00000000000..aee5cefa447 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "referencing_function_parameters" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/src/main.sw new file mode 100644 index 00000000000..95f38037aae --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/src/main.sw @@ -0,0 +1,230 @@ +script; + +use core::ops::Eq; + +struct S { + x: u8, +} + +impl S { + fn new() -> Self { + Self { x: 0 } + } + + fn use_me(self) { + poke(self.x); + } +} + +impl Eq for S { + fn eq(self, other: Self) -> bool { + self.x == other.x + } +} + +// TODO-IG: Uncomment once proper referencing of copy type parameters is implemented. +//#[inline(always)] +//Fn u8_parameter(p: u8) { +// let r_p_1 = &p; +// let r_p_2 = &p; +// +// let p_ptr = asm(r: &p) { r: raw_ptr }; +// let r_p_1_ptr = asm(r: r_p_1) { r: raw_ptr }; +// let r_p_2_ptr = asm(r: r_p_2) { r: raw_ptr }; +// +// assert(p_ptr == r_p_1_ptr); +// assert(p_ptr == r_p_2_ptr); +// +// assert(p_ptr.read::() == p); +//} +// +//#[inline(never)] +//Fn u8_parameter_not_inlined(p: u8) { +// u8_parameter(p) +//} + +impl Eq for [u64;2] { + fn eq(self, other: Self) -> bool { + self[0] == other[0] && self[1] == other[1] + } +} + +#[inline(always)] +fn array_parameter(p: [u64;2]) { + let r_p_1 = &p; + let r_p_2 = &p; + + let p_ptr = asm(r: &p) { r: raw_ptr }; + let r_p_1_ptr = asm(r: r_p_1) { r: raw_ptr }; + let r_p_2_ptr = asm(r: r_p_2) { r: raw_ptr }; + + assert(p_ptr == r_p_1_ptr); + assert(p_ptr == r_p_2_ptr); + + assert(p_ptr.read::<[u64;2]>() == p); + + assert(*r_p_1 == *r_p_2); +} + +#[inline(never)] +fn array_parameter_not_inlined(p: [u64;2]) { + array_parameter(p) +} + +struct EmptyStruct { } + +impl Eq for EmptyStruct { + fn eq(self, other: Self) -> bool { + true + } +} + +#[inline(always)] +fn empty_struct_parameter(p: EmptyStruct) { + let r_p_1 = &p; + let r_p_2 = &p; + + let p_ptr = asm(r: &p) { r: raw_ptr }; + let r_p_1_ptr = asm(r: r_p_1) { r: raw_ptr }; + let r_p_2_ptr = asm(r: r_p_2) { r: raw_ptr }; + + assert(p_ptr == r_p_1_ptr); + assert(p_ptr == r_p_2_ptr); + + assert(p_ptr.read::() == p); + + assert(*r_p_1 == *r_p_2); +} + +#[inline(never)] +fn empty_struct_parameter_not_inlined(p: EmptyStruct) { + empty_struct_parameter(p) +} + +#[inline(always)] +fn struct_parameter(p: S) { + let r_p_1 = &p; + let r_p_2 = &p; + + let p_ptr = asm(r: &p) { r: raw_ptr }; + let r_p_1_ptr = asm(r: r_p_1) { r: raw_ptr }; + let r_p_2_ptr = asm(r: r_p_2) { r: raw_ptr }; + + assert(p_ptr == r_p_1_ptr); + assert(p_ptr == r_p_2_ptr); + + assert(p_ptr.read::() == p); + + assert(*r_p_1 == *r_p_2); +} + +#[inline(never)] +fn struct_parameter_not_inlined(p: S) { + struct_parameter(p) +} + +enum E { + A: u8, +} + +impl Eq for E { + fn eq(self, other: Self) -> bool { + match (self, other) { + (E::A(r), E::A(l)) => r == l, + } + } +} + +#[inline(always)] +fn enum_parameter(p: E) { + let r_p_1 = &p; + let r_p_2 = &p; + + let p_ptr = asm(r: &p) { r: raw_ptr }; + let r_p_1_ptr = asm(r: r_p_1) { r: raw_ptr }; + let r_p_2_ptr = asm(r: r_p_2) { r: raw_ptr }; + + assert(p_ptr == r_p_1_ptr); + assert(p_ptr == r_p_2_ptr); + + assert(p_ptr.read::() == p); + + assert(*r_p_1 == *r_p_2); +} + +#[inline(never)] +fn enum_parameter_not_inlined(p: E) { + enum_parameter(p) +} + +#[inline(always)] +fn generic_parameter() { + // TODO-IG: Uncomment once referencing copy type function parameters is implemented. + //generic_parameter_test(123u8); + //generic_parameter_test(123u64); + //generic_parameter_test(true); + + //let s = S { x: 0 }; + //let ptr_s = __addr_of(s); + + //generic_parameter_test(ptr_s); + + generic_parameter_test(S { x: 123u8 }); + generic_parameter_test(EmptyStruct { }); + generic_parameter_test([123u64, 123u64]); + generic_parameter_test(E::A(123u8)); +} + +#[inline(always)] +fn generic_parameter_test(p: T) where T: Eq { + let r_p_1 = &p; + let r_p_2 = &p; + + let p_ptr = asm(r: &p) { r: raw_ptr }; + let r_p_1_ptr = asm(r: r_p_1) { r: raw_ptr }; + let r_p_2_ptr = asm(r: r_p_2) { r: raw_ptr }; + + assert(p_ptr == r_p_1_ptr); + assert(p_ptr == r_p_2_ptr); + + assert(p_ptr.read::() == p); + + assert(*r_p_1 == *r_p_2); +} + +#[inline(never)] +fn generic_parameter_not_inlined() { + generic_parameter() +} + +#[inline(never)] +fn test_all_inlined() { + //u8_parameter(123u8); + array_parameter([111u64, 222u64]); + empty_struct_parameter(EmptyStruct { }); + struct_parameter(S { x: 123u8 }); + enum_parameter(E::A(123u8)); + generic_parameter(); +} + +#[inline(never)] +fn test_not_inlined() { + //u8_parameter_not_inlined(123u8); + array_parameter_not_inlined([111u64, 222u64]); + empty_struct_parameter_not_inlined(EmptyStruct { }); + struct_parameter_not_inlined(S { x: 123u8 }); + enum_parameter_not_inlined(E::A(123u8)); + generic_parameter_not_inlined(); +} + +fn main() -> u64 { + test_all_inlined(); + test_not_inlined(); + + S::new().use_me(); + + 42 +} + +#[inline(never)] +fn poke(_x: T) { } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/test.toml new file mode 100644 index 00000000000..90de30d80ec --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_function_parameters/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 0 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/Forc.lock new file mode 100644 index 00000000000..83a7c97123e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-A0241DEA23965530" + +[[package]] +name = "referencing_local_vars_and_values" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-A0241DEA23965530" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/Forc.toml new file mode 100644 index 00000000000..3fe2427d3dd --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "referencing_local_vars_and_values" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/src/impls.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/src/impls.sw new file mode 100644 index 00000000000..4d722f6cba1 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/src/impls.sw @@ -0,0 +1,229 @@ +library; + +use core::ops::Eq; +use std::bytes_conversions::u256::*; +use std::bytes_conversions::b256::*; + +pub trait New { + fn new() -> Self; +} + +pub trait ZeroSize { } + +impl New for bool { + fn new() -> Self { + true + } +} + +impl New for u8 { + fn new() -> Self { + 123 + } +} + +impl New for u16 { + fn new() -> Self { + 1234 + } +} + +impl New for u32 { + fn new() -> Self { + 12345 + } +} + +impl New for u64 { + fn new() -> Self { + 123456 + } +} + +impl New for u256 { + fn new() -> Self { + // We cannot have a constants here, because it would + // end up being a reference type constant which means + // we will get the same reference for each `new()` + // instance which breaks the semantics of the test. + // That's why this manual creation here. + let mut bytes = std::bytes::Bytes::with_capacity(32); + let mut i: u8 = 0; + while i < 32_u8 { + bytes.push(32_u8 - i); + i += 1_u8; + } + + u256::from_le_bytes(bytes) + } +} + +impl New for str { + fn new() -> Self { + "1a2B3c" + } +} + +impl Eq for str[6] { + fn eq(self, other: Self) -> bool { + let mut i = 0; + while i < 6 { + let ptr_self = __addr_of(self).add::(i); + let ptr_other = __addr_of(other).add::(i); + + if ptr_self.read::() != ptr_other.read::() { + return false; + } + + i = i + 1; + }; + + true + } +} + +impl New for str[6] { + fn new() -> Self { + __to_str_array("1a2B3c") + } +} + +impl Eq for [u64;2] { + fn eq(self, other: Self) -> bool { + self[0] == other[0] && self[1] == other[1] + } +} + +impl New for [u64;2] { + fn new() -> Self { + [123456, 654321] + } +} + +pub struct Struct { + x: u64, +} + +impl Eq for Struct { + fn eq(self, other: Self) -> bool { + self.x == other.x + } +} + +impl New for Struct { + fn new() -> Self { + Self { x: 98765 } + } +} + +pub struct EmptyStruct { } + +impl Eq for EmptyStruct { + fn eq(self, other: Self) -> bool { + true + } +} + +impl New for EmptyStruct { + fn new() -> Self { + EmptyStruct { } + } +} + +impl ZeroSize for EmptyStruct { } + +pub enum Enum { + A: u64, +} + +impl Eq for Enum { + fn eq(self, other: Self) -> bool { + match (self, other) { + (Enum::A(l), Enum::A(r)) => l == r, + } + } +} + +impl New for Enum { + fn new() -> Self { + Self::A(123456) + } +} + +impl Eq for (u8, u32) { + fn eq(self, other: Self) -> bool { + self.0 == other.0 && self.1 == other.1 + } +} + +impl New for (u8, u32) { + fn new() -> Self { + (123, 12345) + } +} + +impl New for b256 { + fn new() -> Self { + // We cannot have a constants here, because it would + // end up being a reference type constant which means + // we will get the same reference for each `new()` + // instance which breaks the semantics of the test. + // That's why this manual creation here. + let mut bytes = std::bytes::Bytes::with_capacity(32); + let mut i: u8 = 0; + while i < 32_u8 { + bytes.push(32_u8 - i); + i += 1_u8; + } + + b256::from_le_bytes(bytes) + } +} + +impl New for raw_ptr { + fn new() -> Self { + let null_ptr = asm() { zero: raw_ptr }; + + null_ptr.add::(42) + } +} + +impl New for raw_slice { + fn new() -> Self { + let null_ptr = asm() { zero: raw_ptr }; + + std::raw_slice::from_parts::(null_ptr, 42) + } +} + +impl Eq for raw_slice { + fn eq(self, other: Self) -> bool { + self.ptr() == other.ptr() && self.number_of_bytes() == other.number_of_bytes() + } +} + +impl New for () { + fn new() -> Self { + () + } +} + +impl Eq for () { + fn eq(self, other: Self) -> bool { + true + } +} + +impl New for [u64;0] { + fn new() -> Self { + [] + } +} + +impl Eq for [u64;0] { + fn eq(self, other: Self) -> bool { + true + } +} + +impl ZeroSize for [u64;0] { } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/src/main.sw new file mode 100644 index 00000000000..f94d3073609 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/src/main.sw @@ -0,0 +1,261 @@ +script; + +mod impls; + +use impls::*; + +use core::ops::Eq; + +#[inline(always)] +fn reference_local_var_and_value() + where T: Eq + New +{ + let x = T::new(); + + let r_x_1 = &x; + let r_x_2 = &x; + let r_val = &T::new(); + + let r_x_1_ptr = asm(r: r_x_1) { r: raw_ptr }; + let r_x_2_ptr = asm(r: r_x_2) { r: raw_ptr }; + let r_val_ptr = asm(r: r_val) { r: raw_ptr }; + + assert(r_x_1_ptr == r_x_2_ptr); + assert(r_x_1_ptr != r_val_ptr); + + let r_x_1_ptr_val = r_x_1_ptr.read::(); + let r_x_2_ptr_val = r_x_2_ptr.read::(); + let r_x_val_val = r_val_ptr.read::(); + + assert(r_x_1_ptr_val == x); + assert(r_x_2_ptr_val == x); + assert(r_x_val_val == T::new()); + + assert(*r_x_1 == x); + assert(*r_x_2 == x); + assert(*r_val == T::new()); +} + +#[inline(never)] +fn reference_local_var_and_value_not_inlined() + where T: Eq + New +{ + reference_local_var_and_value::() +} + +#[inline(always)] +fn reference_local_reference_var_and_value() + where T: Eq + New +{ + let x = T::new(); + let r_x = &x; + + let r_r_x_1 = & &x; + let r_r_x_2 = & &x; + let r_r_val = & &T::new(); + + let r_r_x_a = &r_x; + let r_r_x_b = &r_x; + + let r_r_x_1_ptr = asm(r: r_r_x_1) { r: raw_ptr }; + let r_r_x_2_ptr = asm(r: r_r_x_2) { r: raw_ptr }; + let r_r_val_ptr = asm(r: r_r_val) { r: raw_ptr }; + + let r_r_x_a_ptr = asm(r: r_r_x_a) { r: raw_ptr }; + let r_r_x_b_ptr = asm(r: r_r_x_b) { r: raw_ptr }; + + assert(r_r_x_1_ptr != r_r_x_2_ptr); + assert(r_r_x_1_ptr != r_r_val_ptr); + + assert(r_r_x_a_ptr == r_r_x_b_ptr); + + assert(**r_r_x_1 == x); + assert(**r_r_x_2 == x); + assert(**r_r_val == T::new()); + assert(**r_r_x_a == x); + assert(**r_r_x_b == x); + + let r_r_x_1_ptr_ptr = r_r_x_1_ptr.read::(); + let r_r_x_2_ptr_ptr = r_r_x_2_ptr.read::(); + let r_r_val_ptr_ptr = r_r_val_ptr.read::(); + + let r_r_x_a_ptr_ptr = r_r_x_a_ptr.read::(); + let r_r_x_b_ptr_ptr = r_r_x_b_ptr.read::(); + + assert(r_r_x_1_ptr_ptr == r_r_x_2_ptr_ptr); + assert(r_r_x_1_ptr_ptr != r_r_val_ptr_ptr); + assert(r_r_x_a_ptr_ptr == r_r_x_b_ptr_ptr); + assert(r_r_x_a_ptr_ptr != r_r_val_ptr_ptr); + + let r_r_x_1_ptr_ptr_val = r_r_x_1_ptr_ptr.read::(); + let r_r_x_2_ptr_ptr_val = r_r_x_2_ptr_ptr.read::(); + let r_r_val_ptr_ptr_val = r_r_val_ptr_ptr.read::(); + + let r_r_x_a_ptr_ptr_val = r_r_x_a_ptr_ptr.read::(); + let r_r_x_b_ptr_ptr_val = r_r_x_b_ptr_ptr.read::(); + + assert(r_r_x_1_ptr_ptr_val == x); + assert(r_r_x_2_ptr_ptr_val == x); + assert(r_r_x_a_ptr_ptr_val == x); + assert(r_r_x_b_ptr_ptr_val == x); + assert(r_r_val_ptr_ptr_val == T::new()); +} + +#[inline(never)] +fn reference_local_reference_var_and_value_not_inlined() + where T: Eq + New +{ + reference_local_reference_var_and_value::() +} + +#[inline(always)] +fn reference_zero_sized_local_var_and_value(is_inlined: bool) + where T: Eq + New + ZeroSize +{ + assert(__size_of::() == 0); + + let x = T::new(); + + let r_x_1 = &x; + let r_x_2 = &x; + let r_val = &T::new(); + + let r_dummy = &123u64; + + let r_x_1_ptr = asm(r: r_x_1) { r: raw_ptr }; + let r_x_2_ptr = asm(r: r_x_2) { r: raw_ptr }; + let r_val_ptr = asm(r: r_val) { r: raw_ptr }; + let r_dummy_ptr = asm(r: r_dummy) { r: raw_ptr }; + + // If there is no inlining and mixing with other test functions, + // since the size of `T` is zero, means allocates zero memory, + // both created values will be on the same memory location. + // The dummy value will also be on the same location. + // In case of inlining with other test functions we can get + // the two variables position separately from each other, intermixed + // with the locals coming from other functions. + // Note that we rely on the optimization which will remove the local + // variables for the references. This assumption is fine, + // the test should never be flaky. + if (!is_inlined) { + assert(r_x_1_ptr == r_val_ptr); + assert(r_x_1_ptr == r_dummy_ptr); + } + + assert(r_x_1_ptr == r_x_2_ptr); + + let r_x_1_ptr_val = r_x_1_ptr.read::(); + let r_x_2_ptr_val = r_x_2_ptr.read::(); + let r_x_val_val = r_val_ptr.read::(); + let r_dummy_val = r_dummy_ptr.read::(); + + assert(r_x_1_ptr_val == x); + assert(r_x_2_ptr_val == x); + assert(r_x_val_val == T::new()); + assert(r_dummy_val == 123); + + assert(*r_x_1 == x); + assert(*r_x_2 == x); + assert(*r_val == T::new()); + assert(*r_dummy == 123); +} + +#[inline(never)] +fn reference_zero_sized_local_var_and_value_not_inlined() + where T: Eq + New + ZeroSize +{ + reference_zero_sized_local_var_and_value::(false) +} + +#[inline(never)] +fn test_all_inlined() { + reference_local_var_and_value::<()>(); + reference_local_var_and_value::(); + reference_local_var_and_value::(); + reference_local_var_and_value::(); + reference_local_var_and_value::(); + reference_local_var_and_value::(); + reference_local_var_and_value::(); + reference_local_var_and_value::<[u64;2]>(); + reference_local_var_and_value::(); + reference_local_var_and_value::(); + reference_local_var_and_value::(); + reference_local_var_and_value::(); + reference_local_var_and_value::<(u8, u32)>(); + reference_local_var_and_value::(); + reference_local_var_and_value::(); + reference_local_var_and_value::(); + + reference_zero_sized_local_var_and_value::(true); + reference_zero_sized_local_var_and_value::<[u64;0]>(true); + + reference_local_reference_var_and_value::<()>(); + reference_local_reference_var_and_value::(); + reference_local_reference_var_and_value::(); + reference_local_reference_var_and_value::(); + reference_local_reference_var_and_value::(); + reference_local_reference_var_and_value::(); + reference_local_reference_var_and_value::(); + reference_local_reference_var_and_value::<[u64;2]>(); + reference_local_reference_var_and_value::(); + reference_local_reference_var_and_value::(); + reference_local_reference_var_and_value::(); + reference_local_reference_var_and_value::(); + reference_local_reference_var_and_value::<(u8, u32)>(); + reference_local_reference_var_and_value::(); + reference_local_reference_var_and_value::(); + reference_local_reference_var_and_value::(); + + // Note: we cannot have equivalent tests here for zero-size + // types because we cannot have expectations of the ordering + // in memory like we had in a simple case with references on + // zero-size types. Also, references to references might + // be allocated as local variables. +} + +#[inline(never)] +fn test_not_inlined() { + reference_local_var_and_value_not_inlined::<()>(); + reference_local_var_and_value_not_inlined::(); + reference_local_var_and_value_not_inlined::(); + reference_local_var_and_value_not_inlined::(); + reference_local_var_and_value_not_inlined::(); + reference_local_var_and_value_not_inlined::(); + reference_local_var_and_value_not_inlined::(); + reference_local_var_and_value_not_inlined::<[u64;2]>(); + reference_local_var_and_value_not_inlined::(); + reference_local_var_and_value_not_inlined::(); + reference_local_var_and_value_not_inlined::(); + reference_local_var_and_value_not_inlined::(); + reference_local_var_and_value_not_inlined::<(u8, u32)>(); + reference_local_var_and_value_not_inlined::(); + reference_local_var_and_value_not_inlined::(); + reference_local_var_and_value_not_inlined::(); + + reference_zero_sized_local_var_and_value_not_inlined::(); + reference_zero_sized_local_var_and_value_not_inlined::<[u64;0]>(); + + reference_local_reference_var_and_value_not_inlined::<()>(); + reference_local_reference_var_and_value_not_inlined::(); + reference_local_reference_var_and_value_not_inlined::(); + reference_local_reference_var_and_value_not_inlined::(); + reference_local_reference_var_and_value_not_inlined::(); + reference_local_reference_var_and_value_not_inlined::(); + reference_local_reference_var_and_value_not_inlined::(); + reference_local_reference_var_and_value_not_inlined::<[u64;2]>(); + reference_local_reference_var_and_value_not_inlined::(); + reference_local_reference_var_and_value_not_inlined::(); + reference_local_reference_var_and_value_not_inlined::(); + reference_local_reference_var_and_value_not_inlined::(); + reference_local_reference_var_and_value_not_inlined::<(u8, u32)>(); + reference_local_reference_var_and_value_not_inlined::(); + reference_local_reference_var_and_value_not_inlined::(); + reference_local_reference_var_and_value_not_inlined::(); +} + +fn main() -> u64 { + test_all_inlined(); + test_not_inlined(); + + 42 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/test.toml new file mode 100644 index 00000000000..764b3a28359 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_local_vars_and_values/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 9 # TODO-IG: Should be zero. DCA problem? Investigate why there are "This method is never called." errors for some of the types. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/Forc.lock new file mode 100644 index 00000000000..b69324d677b --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-9D780D7852006E10" + +[[package]] +name = "referencing_parts_of_aggregates" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-9D780D7852006E10" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/Forc.toml new file mode 100644 index 00000000000..e06b38e90ee --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "referencing_parts_of_aggregates" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/src/main.sw new file mode 100644 index 00000000000..8a7cd641031 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/src/main.sw @@ -0,0 +1,258 @@ +script; + +struct A { + x: u8, + r_x: &u8, +} + +struct B { + a: A, + r_a: &A, +} + +struct C { + b: B, + r_b: &B, +} + +impl A { + fn new() -> Self { + Self { x: 0, r_x: &0 } + } + + fn use_me(self) { + poke(self.x); + poke(self.r_x); + } +} + +impl B { + fn new() -> Self { + Self { a: A::new(), r_a: &A::new() } + } + + fn use_me(self) { + poke(self.a); + poke(self.r_a); + } +} + +impl C { + fn new() -> Self { + Self { b: B::new(), r_b: &B::new() } + } + + fn use_me(self) { + poke(self.b); + poke(self.r_b); + } +} + +// TODO-IG: Add tests for accessing via reference chains once dereferencing operators `[]` and `.` are implemented. + +#[inline(always)] +fn struct_fields() { + let mut x = 123u8; + + let a = A { x, r_x: &x }; + let b = B { a, r_a: &a }; + let c = C { b, r_b: &b }; + + let r_a_x: &u8 = &a.x; + let r_a_r_x: & &u8 = &a.r_x; + + let r_a_x_ptr = asm(r: r_a_x) { r: raw_ptr }; + let r_a_r_x_ptr = asm(r: r_a_r_x) { r: raw_ptr }; + + assert(r_a_x_ptr.read::() == x); + assert(r_a_r_x_ptr.read::().read::() == x); + + assert(*r_a_x == x); + assert(**r_a_r_x == x); + + let r_c_b_a_x: &u8 = &c.b.a.x; + let r_c_b_a_r_x: & &u8 = &c.b.a.r_x; + + let r_c_b_a_x_ptr = asm(r: r_c_b_a_x) { r: raw_ptr }; + let r_c_b_a_r_x_ptr = asm(r: r_c_b_a_r_x) { r: raw_ptr }; + + assert(r_c_b_a_x_ptr.read::() == x); + assert(r_c_b_a_r_x_ptr.read::().read::() == x); + + assert(*r_c_b_a_x == x); + assert(**r_c_b_a_r_x == x); +} + +#[inline(never)] +fn struct_fields_not_inlined() { + struct_fields() +} + +#[inline(always)] +fn tuple_fields() { + let x = 123u8; + + let t1 = (x, &x); + let t2 = (t1, &t1); + let t3 = (t2, &t2); + + let r_t1_x: &u8 = &t1.0; + let r_t1_r_x: & &u8 = &t1.1; + + let r_t1_x_ptr = asm(r: r_t1_x) { r: raw_ptr }; + let r_t1_r_x_ptr = asm(r: r_t1_r_x) { r: raw_ptr }; + + assert(r_t1_x_ptr.read::() == x); + assert(r_t1_r_x_ptr.read::().read::() == x); + + assert(*r_t1_x == x); + assert(**r_t1_r_x == x); + + let r_t3_t2_t1_x: &u8 = &t3.0.0.0; + let r_t3_t2_t1_r_x: & &u8 = &t3.0.0.1; + + let r_t3_t2_t1_x_ptr = asm(r: r_t3_t2_t1_x) { r: raw_ptr }; + let r_t3_t2_t1_r_x_ptr = asm(r: r_t3_t2_t1_r_x) { r: raw_ptr }; + + assert(r_t3_t2_t1_x_ptr.read::() == x); + assert(r_t3_t2_t1_r_x_ptr.read::().read::() == x); + + assert(*r_t3_t2_t1_x == x); + assert(**r_t3_t2_t1_r_x == x); +} + +#[inline(never)] +fn tuple_fields_not_inlined() { + tuple_fields() +} + +#[inline(always)] +fn array_elements() { + // TODO-IG: Add tests for arrays of references once dereferencing operator `[]` is implemented. + let x1 = 111u8; + let x2 = 222u8; + + let a1 = [x1, x2]; + let a2 = [a1, a1]; + let a3 = [a2, a2]; + + let r_a1_x1: &u8 = &a1[0]; + let r_a1_x2: &u8 = &a1[1]; + + let r_a1_x1_ptr = asm(r: r_a1_x1) { r: raw_ptr }; + let r_a1_x2_ptr = asm(r: r_a1_x2) { r: raw_ptr }; + + assert(r_a1_x1_ptr.read::() == x1); + assert(r_a1_x2_ptr.read::() == x2); + + assert(*r_a1_x1 == x1); + assert(*r_a1_x2 == x2); + + let r_a3_a2_a1_x1: &u8 = &a3[0][1][0]; + let r_a3_a2_a1_x2: &u8 = &a3[1][0][1]; + + let r_a3_a2_a1_x1_ptr = asm(r: r_a3_a2_a1_x1) { r: raw_ptr }; + let r_a3_a2_a1_x2_ptr = asm(r: r_a3_a2_a1_x2) { r: raw_ptr }; + + assert(r_a3_a2_a1_x1_ptr.read::() == x1); + assert(r_a3_a2_a1_x2_ptr.read::() == x2); + + assert(*r_a3_a2_a1_x1 == x1); + assert(*r_a3_a2_a1_x2 == x2); +} + +#[inline(never)] +fn array_elements_not_inlined() { + array_elements() +} + +struct S { + a: [(u32, u32);2] +} + +#[inline(always)] +fn all_in_one() { + let s = S { a: [(222, 333), (444, 555)] }; + + let r_222: &u32 = &s.a[0].0; + let r_555: &u32 = &s.a[1].1; + + let r_222_ptr = asm(r: r_222) { r: raw_ptr }; + let r_555_ptr = asm(r: r_555) { r: raw_ptr }; + + assert(r_222_ptr.read::() == 222); + assert(r_555_ptr.read::() == 555); + + assert(*r_222 == 222); + assert(*r_555 == 555); + + // ---- + + let s1 = S { a: [(1222, 1333), (1444, 1555)] }; + let s2 = S { a: [(2222, 2333), (2444, 2555)] }; + + let a = [(s, s1), (s1, s2), (s, s2)]; + + let r_1555 = &a[1].0.a[1].1; + let r_2333 = &a[2].1.a[0].1; + + let r_1555_ptr = asm(r: r_1555) { r: raw_ptr }; + let r_2333_ptr = asm(r: r_2333) { r: raw_ptr }; + + assert(r_1555_ptr.read::() == 1555); + assert(r_2333_ptr.read::() == 2333); + + assert(*r_1555 == 1555); + assert(*r_2333 == 2333); + + // ---- + + let t = ([s, s1], [s1, s2], [s, s2]); + + let r_1555 = &t.1[0].a[1].1; + let r_2333 = &t.2[1].a[0].1; + + let r_1555_ptr = asm(r: r_1555) { r: raw_ptr }; + let r_2333_ptr = asm(r: r_2333) { r: raw_ptr }; + + assert(r_1555_ptr.read::() == 1555); + assert(r_2333_ptr.read::() == 2333); + + assert(*r_1555 == 1555); + assert(*r_2333 == 2333); +} + +#[inline(never)] +fn all_in_one_not_inlined() { + all_in_one() +} + +#[inline(never)] +fn test_all_inlined() { + struct_fields(); + tuple_fields(); + array_elements(); + all_in_one(); +} + +#[inline(never)] +fn test_not_inlined() { + struct_fields_not_inlined(); + tuple_fields_not_inlined(); + array_elements_not_inlined(); + all_in_one_not_inlined(); +} + +fn main() -> u64 { + test_all_inlined(); + test_not_inlined(); + + A::new().use_me(); + B::new().use_me(); + C::new().use_me(); + + 42 +} + +#[inline(never)] +fn poke(_x: T) { } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/test.toml new file mode 100644 index 00000000000..90de30d80ec --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_parts_of_aggregates/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 0 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/Forc.lock new file mode 100644 index 00000000000..899a58c065e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-EFEB9230F6720AC3" + +[[package]] +name = "referencing_references" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-EFEB9230F6720AC3" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/Forc.toml new file mode 100644 index 00000000000..12296492b2f --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "referencing_references" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/json_abi_oracle.json new file mode 100644 index 00000000000..ad50b55d54c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/json_abi_oracle.json @@ -0,0 +1,25 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/src/main.sw new file mode 100644 index 00000000000..83751bae140 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/src/main.sw @@ -0,0 +1,84 @@ +script; + +#[inline(always)] +fn referencing_references() { + let x = 123u8; + + let r_x = &x; + + let r_x_1 = &x; + let r_x_2 = &x; + + let r_r_x_1 = &r_x_1; + let r_r_x_2 = &r_x_2; + + let r_r_x = &r_x; + let r_r_r_x = &r_r_x; + + // TODO-IG: Remove space once parsing supports `&&&..&&x`. + let r_r_x_chain = & &x; + let r_r_r_x_chain = & & &x; + + let r_x_ptr = asm(r: r_x) { r: raw_ptr }; + let r_x_1_ptr = asm(r: r_x_1) { r: raw_ptr }; + let r_x_2_ptr = asm(r: r_x_2) { r: raw_ptr }; + + assert(r_x_ptr == r_x_1_ptr); + assert(r_x_ptr == r_x_2_ptr); + + let r_r_x_1_ptr = asm(r: r_r_x_1) { r: raw_ptr }; + let r_r_x_2_ptr = asm(r: r_r_x_2) { r: raw_ptr }; + + let r_r_x_ptr = asm(r: r_r_x) { r: raw_ptr }; + let r_r_r_x_ptr = asm(r: r_r_r_x) { r: raw_ptr }; + + let r_r_x_chain_ptr = asm(r: r_r_x_chain) { r: raw_ptr }; + let r_r_r_x_chain_ptr = asm(r: r_r_r_x_chain) { r: raw_ptr }; + + assert(r_x_ptr != r_r_x_ptr); + assert(r_r_x_ptr != r_r_r_x_ptr); + assert(r_r_r_x_ptr != r_x_ptr); + + // `r_x_1` and `r_x_2` references the same variable `x` + // but they are two different variables. That means that + // the references pointing to them must be different. + // Same is with the `chain` references and their "`chain`-less" + // counterparts. + assert(r_r_x_1_ptr != r_r_x_2_ptr); + + assert(r_r_x_ptr != r_r_x_chain_ptr); + assert(r_r_r_x_ptr != r_r_r_x_chain_ptr); + + let x_via_refs = r_r_r_x_ptr.read::().read::().read::(); + assert(x_via_refs == x); + + assert(*r_x == x); + assert(*r_x_1 == x); + assert(*r_x_2 == x); + assert(**r_r_x_1 == x); + assert(**r_r_x_2 == x); + assert(**r_r_x_chain == x); + assert(***r_r_r_x_chain == x); +} + +#[inline(never)] +fn referencing_references_not_inlined() { + referencing_references() +} + +#[inline(never)] +fn test_all_inlined() { + referencing_references(); +} + +#[inline(never)] +fn test_not_inlined() { + referencing_references_not_inlined(); +} + +fn main() -> u64 { + test_all_inlined(); + test_not_inlined(); + + 42 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/test.toml new file mode 100644 index 00000000000..90de30d80ec --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/referencing_references/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 42 } +validate_abi = true +expected_warnings = 0 From bb1a627757a70ad6d0cbe0bd2c17f0ad1230ad75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaya=20G=C3=B6kalp?= Date: Fri, 5 Jan 2024 01:53:15 +0300 Subject: [PATCH 9/9] ci: use rust 1.75 in CI (#5435) ## Description Bumps CI rust version to 1.75 and fixes new warnings popped up during the process. unblocks #5433 --- .github/workflows/ci.yml | 4 +- forc/src/cli/plugin.rs | 2 +- sway-ast/src/priv_prelude.rs | 15 +- sway-core/src/asm_lang/mod.rs | 12 +- sway-core/src/control_flow_analysis/mod.rs | 3 +- sway-core/src/decl_engine/mapping.rs | 2 +- .../ty/expression/expression_variant.rs | 2 +- .../ast_node/declaration/function.rs | 1 - .../ast_node/declaration/mod.rs | 10 - .../ast_node/expression/intrinsic_function.rs | 6 +- .../ast_node/expression/mod.rs | 1 - .../ast_node/expression/typed_expression.rs | 298 +++++++++--------- .../typed_expression/method_application.rs | 12 +- .../semantic_analysis/type_check_context.rs | 6 +- sway-ir/src/optimize/sroa.rs | 4 +- sway-lsp/src/core/token.rs | 2 +- sway-parse/src/parser.rs | 10 +- sway-parse/src/priv_prelude.rs | 19 +- sway-parse/src/token.rs | 3 +- .../src/sdk-harness/test_projects/auth/mod.rs | 75 +++-- .../test_projects/low_level_call/mod.rs | 3 +- .../test_projects/low_level_call_bytes/mod.rs | 3 +- .../test_projects/storage_access/mod.rs | 10 +- .../test_projects/tx_fields/mod.rs | 5 +- 24 files changed, 252 insertions(+), 256 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c6deb102a0..4904f4a84b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,8 +15,8 @@ concurrency: env: CARGO_TERM_COLOR: always REGISTRY: ghcr.io - RUST_VERSION: 1.73.0 - NIGHTLY_RUST_VERSION: nightly-2023-08-27 + RUST_VERSION: 1.75.0 + NIGHTLY_RUST_VERSION: nightly-2023-12-27 jobs: build-sway-lib-core: diff --git a/forc/src/cli/plugin.rs b/forc/src/cli/plugin.rs index 47d234df4b9..63a661b9725 100644 --- a/forc/src/cli/plugin.rs +++ b/forc/src/cli/plugin.rs @@ -19,7 +19,7 @@ pub(crate) fn execute_external_subcommand( args: Vec, silent: bool, ) -> Result { - let cmd = args.get(0).expect("`args` must not be empty"); + let cmd = args.first().expect("`args` must not be empty"); let args = &args[1..]; let path = find_external_subcommand(cmd); let command = match path { diff --git a/sway-ast/src/priv_prelude.rs b/sway-ast/src/priv_prelude.rs index e02c404f6f2..b799d69f37d 100644 --- a/sway-ast/src/priv_prelude.rs +++ b/sway-ast/src/priv_prelude.rs @@ -1,7 +1,7 @@ pub use { crate::{ assignable::Assignable, - attribute::{Annotated, Attribute, AttributeDecl}, + attribute::Annotated, brackets::{AngleBrackets, Braces, Parens, SquareBrackets}, expr::{ asm::{AsmBlock, AsmImmediate}, @@ -9,7 +9,6 @@ pub use { CodeBlockContents, Expr, }, generics::{GenericArgs, GenericParams}, - intrinsics::*, item::{ item_abi::ItemAbi, item_configurable::ItemConfigurable, @@ -25,22 +24,18 @@ pub use { FnSignature, Item, ItemKind, TraitType, TypeField, }, keywords::*, - literal::{LitBool, LitBoolType, LitChar, LitInt, LitIntType, LitString, Literal}, + literal::Literal, path::{PathExpr, PathType}, pattern::Pattern, punctuated::Punctuated, - statement::{Statement, StatementLet}, + statement::Statement, submodule::Submodule, - token::{Group, Punct, Spacing, TokenStream, TokenTree}, ty::Ty, - where_clause::{WhereBound, WhereClause}, + where_clause::WhereClause, }, extension_trait::extension_trait, num_bigint::BigUint, - serde::{Serialize, Serializer}, - std::{ - fmt, marker::PhantomData, mem, ops::ControlFlow, path::PathBuf, str::FromStr, sync::Arc, - }, + serde::Serialize, sway_types::{ ast::{Delimiter, PunctKind}, Ident, Span, Spanned, diff --git a/sway-core/src/asm_lang/mod.rs b/sway-core/src/asm_lang/mod.rs index 86a2f185a74..19a51d68d07 100644 --- a/sway-core/src/asm_lang/mod.rs +++ b/sway-core/src/asm_lang/mod.rs @@ -675,7 +675,7 @@ fn single_reg( }); } - let reg = match args.get(0) { + let reg = match args.first() { Some(reg) => reg, _ => { return Err( @@ -711,7 +711,7 @@ fn two_regs( }); } - let (reg, reg2) = match (args.get(0), args.get(1)) { + let (reg, reg2) = match (args.first(), args.get(1)) { (Some(reg), Some(reg2)) => (reg, reg2), _ => { return Err( @@ -755,7 +755,7 @@ fn four_regs( }); } - let (reg, reg2, reg3, reg4) = match (args.get(0), args.get(1), args.get(2), args.get(3)) { + let (reg, reg2, reg3, reg4) = match (args.first(), args.get(1), args.get(2), args.get(3)) { (Some(reg), Some(reg2), Some(reg3), Some(reg4)) => (reg, reg2, reg3, reg4), _ => { return Err( @@ -820,7 +820,7 @@ fn three_regs( }); } - let (reg, reg2, reg3) = match (args.get(0), args.get(1), args.get(2)) { + let (reg, reg2, reg3) = match (args.first(), args.get(1), args.get(2)) { (Some(reg), Some(reg2), Some(reg3)) => (reg, reg2, reg3), _ => { return Err( @@ -892,7 +892,7 @@ fn single_reg_imm_18( received: args.len(), }); } - let reg = match args.get(0) { + let reg = match args.first() { Some(reg) => reg, _ => { return Err( @@ -942,7 +942,7 @@ fn two_regs_imm_12( received: args.len(), }); } - let (reg, reg2) = match (args.get(0), args.get(1)) { + let (reg, reg2) = match (args.first(), args.get(1)) { (Some(reg), Some(reg2)) => (reg, reg2), _ => { return Err( diff --git a/sway-core/src/control_flow_analysis/mod.rs b/sway-core/src/control_flow_analysis/mod.rs index 77ecfa71e9f..fca93ce96ee 100644 --- a/sway-core/src/control_flow_analysis/mod.rs +++ b/sway-core/src/control_flow_analysis/mod.rs @@ -39,6 +39,5 @@ mod analyze_return_paths; mod dead_code_analysis; mod flow_graph; -pub use analyze_return_paths::*; -pub use dead_code_analysis::*; + pub use flow_graph::*; diff --git a/sway-core/src/decl_engine/mapping.rs b/sway-core/src/decl_engine/mapping.rs index 9105c5710e9..231a339abb5 100644 --- a/sway-core/src/decl_engine/mapping.rs +++ b/sway-core/src/decl_engine/mapping.rs @@ -132,7 +132,7 @@ impl DeclMapping { let func = engines.de().get(&func_id); let unify_check = UnifyCheck::non_dynamic_equality(engines); - if let (left, Some(right)) = (self_type, func.parameters.get(0)) { + if let (left, Some(right)) = (self_type, func.parameters.first()) { if unify_check.check(left, right.type_argument.type_id) { mapping.push((source_decl_ref, dest_decl_ref)); } diff --git a/sway-core/src/language/ty/expression/expression_variant.rs b/sway-core/src/language/ty/expression/expression_variant.rs index 18d0f550489..cc4d22432c1 100644 --- a/sway-core/src/language/ty/expression/expression_variant.rs +++ b/sway-core/src/language/ty/expression/expression_variant.rs @@ -771,7 +771,7 @@ impl ReplaceDecls for TyExpressionVariant { ref mut arguments, .. } => { - let filter_type_opt = arguments.get(0).map(|(_, arg)| arg.return_type); + let filter_type_opt = arguments.first().map(|(_, arg)| arg.return_type); if let Some(filter_type) = filter_type_opt { let filtered_decl_mapping = 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 8af042894d6..ffe9338a848 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -1,6 +1,5 @@ mod function_parameter; -pub use function_parameter::*; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/mod.rs b/sway-core/src/semantic_analysis/ast_node/declaration/mod.rs index 8b10e8326db..7d12bcd80cf 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/mod.rs @@ -13,14 +13,4 @@ mod trait_fn; mod trait_type; mod type_alias; -pub use abi::*; -pub use function::*; -pub use impl_trait::*; -pub use r#enum::*; -pub use r#struct::*; -pub use r#trait::*; -pub use storage::*; pub(crate) use supertrait::*; -pub use trait_fn::*; -pub use trait_type::*; -pub use type_alias::*; 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 7b709885e37..3643e05173d 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 @@ -749,7 +749,7 @@ fn type_check_state_store_word( TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), None, )); - let type_argument = type_arguments.get(0).map(|targ| { + let type_argument = type_arguments.first().map(|targ| { let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let initial_type_info = type_engine @@ -843,7 +843,7 @@ fn type_check_state_quad( )); let number_of_slots_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), arguments[2].clone())?; - let type_argument = type_arguments.get(0).map(|targ| { + let type_argument = type_arguments.first().map(|targ| { let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); let initial_type_info = type_engine @@ -1298,7 +1298,7 @@ fn type_check_smo( } // Type check the type argument - let type_argument = type_arguments.get(0).map(|targ| { + let type_argument = type_arguments.first().map(|targ| { let mut ctx = ctx .by_ref() .with_help_text("") diff --git a/sway-core/src/semantic_analysis/ast_node/expression/mod.rs b/sway-core/src/semantic_analysis/ast_node/expression/mod.rs index 7b998e18105..d7755a2b6da 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/mod.rs @@ -2,5 +2,4 @@ mod intrinsic_function; mod match_expression; pub mod typed_expression; -pub use intrinsic_function::*; pub(crate) use match_expression::*; 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 584df3233fd..8f0735133bc 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 @@ -2176,6 +2176,155 @@ impl ty::TyExpression { } } +fn check_asm_block_validity( + handler: &Handler, + asm: &AsmExpression, + ctx: &TypeCheckContext, +) -> Result<(), ErrorEmitted> { + // Collect all asm block instructions in the form of `VirtualOp`s + let mut opcodes = vec![]; + for op in &asm.body { + let registers = op + .op_args + .iter() + .map(|reg_name| VirtualRegister::Virtual(reg_name.to_string())) + .collect::>(); + + opcodes.push(( + crate::asm_lang::Op::parse_opcode( + handler, + &op.op_name, + ®isters, + &op.immediate, + op.span.clone(), + )?, + op.op_name.clone(), + op.span.clone(), + )); + } + + // Check #1: Disallow control flow instructions + // + for err in opcodes + .iter() + .filter(|op| { + matches!( + op.0, + VirtualOp::JMP(_) + | VirtualOp::JI(_) + | VirtualOp::JNE(..) + | VirtualOp::JNEI(..) + | VirtualOp::JNZI(..) + | VirtualOp::RET(_) + | VirtualOp::RETD(..) + | VirtualOp::RVRT(..) + ) + }) + .map(|op| CompileError::DisallowedControlFlowInstruction { + name: op.1.to_string(), + span: op.2.clone(), + }) + { + handler.emit_err(err); + } + + // Check #2: Disallow initialized registers from being reassigned in the asm block + // + // 1. Collect all registers that have initializers in the list of arguments + let initialized_registers = asm + .registers + .iter() + .filter(|reg| reg.initializer.is_some()) + .map(|reg| VirtualRegister::Virtual(reg.name.to_string())) + .collect::>(); + + // 2. From the list of `VirtualOp`s, figure out what registers are assigned + let assigned_registers: FxHashSet = + opcodes.iter().fold(FxHashSet::default(), |mut acc, op| { + for u in op.0.def_registers() { + acc.insert(u.clone()); + } + acc + }); + + // 3. Intersect the list of assigned registers with the list of initialized registers + let initialized_and_assigned_registers = assigned_registers + .intersection(&initialized_registers) + .collect::>(); + + // 4. Form all the compile errors given the violating registers above. Obtain span information + // from the original `asm.registers` vector. + for err in asm + .registers + .iter() + .filter(|reg| { + initialized_and_assigned_registers + .contains(&VirtualRegister::Virtual(reg.name.to_string())) + }) + .map(|reg| CompileError::InitializedRegisterReassignment { + name: reg.name.to_string(), + span: reg.name.span(), + }) + { + handler.emit_err(err); + } + + // Check #3: Check if there are uninitialized registers that are read before being written + let mut uninitialized_registers = asm + .registers + .iter() + .filter(|reg| reg.initializer.is_none()) + .map(|reg| { + let span = reg.name.span(); + + // Emit warning if this register shadows a variable + let temp_handler = Handler::default(); + let decl = ctx.namespace.resolve_call_path( + &temp_handler, + ctx.engines, + &CallPath { + prefixes: vec![], + suffix: sway_types::BaseIdent::new(span.clone()), + is_absolute: true, + }, + None, + ); + + if let Ok(ty::TyDecl::VariableDecl(decl)) = decl { + handler.emit_warn(CompileWarning { + span: span.clone(), + warning_content: Warning::UninitializedAsmRegShadowsVariable { + name: decl.name.clone(), + }, + }); + } + + (VirtualRegister::Virtual(reg.name.to_string()), span) + }) + .collect::>(); + + for (op, _, _) in opcodes.iter() { + for being_read in op.use_registers() { + if let Some(span) = uninitialized_registers.remove(being_read) { + handler.emit_err(CompileError::UninitRegisterInAsmBlockBeingRead { span }); + } + } + + for being_written in op.def_registers() { + uninitialized_registers.remove(being_written); + } + } + + if let Some((reg, _)) = asm.returns.as_ref() { + let reg = VirtualRegister::Virtual(reg.name.to_string()); + if let Some(span) = uninitialized_registers.remove(®) { + handler.emit_err(CompileError::UninitRegisterInAsmBlockBeingRead { span }); + } + } + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; @@ -2366,152 +2515,3 @@ mod tests { assert!(warnings.is_empty() && errors.is_empty()); } } - -fn check_asm_block_validity( - handler: &Handler, - asm: &AsmExpression, - ctx: &TypeCheckContext, -) -> Result<(), ErrorEmitted> { - // Collect all asm block instructions in the form of `VirtualOp`s - let mut opcodes = vec![]; - for op in &asm.body { - let registers = op - .op_args - .iter() - .map(|reg_name| VirtualRegister::Virtual(reg_name.to_string())) - .collect::>(); - - opcodes.push(( - crate::asm_lang::Op::parse_opcode( - handler, - &op.op_name, - ®isters, - &op.immediate, - op.span.clone(), - )?, - op.op_name.clone(), - op.span.clone(), - )); - } - - // Check #1: Disallow control flow instructions - // - for err in opcodes - .iter() - .filter(|op| { - matches!( - op.0, - VirtualOp::JMP(_) - | VirtualOp::JI(_) - | VirtualOp::JNE(..) - | VirtualOp::JNEI(..) - | VirtualOp::JNZI(..) - | VirtualOp::RET(_) - | VirtualOp::RETD(..) - | VirtualOp::RVRT(..) - ) - }) - .map(|op| CompileError::DisallowedControlFlowInstruction { - name: op.1.to_string(), - span: op.2.clone(), - }) - { - handler.emit_err(err); - } - - // Check #2: Disallow initialized registers from being reassigned in the asm block - // - // 1. Collect all registers that have initializers in the list of arguments - let initialized_registers = asm - .registers - .iter() - .filter(|reg| reg.initializer.is_some()) - .map(|reg| VirtualRegister::Virtual(reg.name.to_string())) - .collect::>(); - - // 2. From the list of `VirtualOp`s, figure out what registers are assigned - let assigned_registers: FxHashSet = - opcodes.iter().fold(FxHashSet::default(), |mut acc, op| { - for u in op.0.def_registers() { - acc.insert(u.clone()); - } - acc - }); - - // 3. Intersect the list of assigned registers with the list of initialized registers - let initialized_and_assigned_registers = assigned_registers - .intersection(&initialized_registers) - .collect::>(); - - // 4. Form all the compile errors given the violating registers above. Obtain span information - // from the original `asm.registers` vector. - for err in asm - .registers - .iter() - .filter(|reg| { - initialized_and_assigned_registers - .contains(&VirtualRegister::Virtual(reg.name.to_string())) - }) - .map(|reg| CompileError::InitializedRegisterReassignment { - name: reg.name.to_string(), - span: reg.name.span(), - }) - { - handler.emit_err(err); - } - - // Check #3: Check if there are uninitialized registers that are read before being written - let mut uninitialized_registers = asm - .registers - .iter() - .filter(|reg| reg.initializer.is_none()) - .map(|reg| { - let span = reg.name.span(); - - // Emit warning if this register shadows a variable - let temp_handler = Handler::default(); - let decl = ctx.namespace.resolve_call_path( - &temp_handler, - ctx.engines, - &CallPath { - prefixes: vec![], - suffix: sway_types::BaseIdent::new(span.clone()), - is_absolute: true, - }, - None, - ); - - if let Ok(ty::TyDecl::VariableDecl(decl)) = decl { - handler.emit_warn(CompileWarning { - span: span.clone(), - warning_content: Warning::UninitializedAsmRegShadowsVariable { - name: decl.name.clone(), - }, - }); - } - - (VirtualRegister::Virtual(reg.name.to_string()), span) - }) - .collect::>(); - - for (op, _, _) in opcodes.iter() { - for being_read in op.use_registers() { - if let Some(span) = uninitialized_registers.remove(being_read) { - handler.emit_err(CompileError::UninitRegisterInAsmBlockBeingRead { span }); - } - } - - for being_written in op.def_registers() { - uninitialized_registers.remove(being_written); - } - } - - if let Some((reg, _)) = asm.returns.as_ref() { - let reg = VirtualRegister::Virtual(reg.name.to_string()); - if let Some(span) = uninitialized_registers.remove(®) { - handler.emit_err(CompileError::UninitRegisterInAsmBlockBeingRead { span }); - } - } - - Ok(()) -} 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 75b27835b05..8833d61cfb0 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 @@ -167,7 +167,7 @@ pub(crate) fn type_check_method_application( let mut is_method_call_syntax_used = false; if !method.is_contract_call { if let MethodName::FromModule { ref method_name } = method_name_binding.inner { - if let Some(first_arg) = args_buf.get(0) { + if let Some(first_arg) = args_buf.front() { // check if the user calls an ABI supertrait's method (those are private) // as a contract method if let TypeInfo::ContractCaller { .. } = &*type_engine.get(first_arg.return_type) { @@ -182,7 +182,7 @@ pub(crate) fn type_check_method_application( is_method_call_syntax_used = true; let is_first_param_self = method .parameters - .get(0) + .first() .map(|f| f.is_self()) .unwrap_or_default(); if !is_first_param_self { @@ -244,7 +244,7 @@ pub(crate) fn type_check_method_application( expression: exp, .. }), Some(ty::TyFunctionParameter { is_mutable, .. }), - ) = (args_buf.get(0), method.parameters.get(0)) + ) = (args_buf.front(), method.parameters.first()) { if *is_mutable { mutability_check(handler, &ctx, &method_name_binding, &span, exp)?; @@ -463,7 +463,7 @@ pub(crate) fn resolve_method_name( } else { let mut module_path = call_path.prefixes.clone(); if let (Some(root_mod), Some(root_name)) = ( - module_path.get(0).cloned(), + module_path.first().cloned(), ctx.namespace.root().name.clone(), ) { if root_mod.as_str() == root_name.as_str() { @@ -475,7 +475,7 @@ pub(crate) fn resolve_method_name( // find the type of the first argument let type_id = arguments - .get(0) + .front() .map(|x| x.return_type) .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Unknown, None)); @@ -499,7 +499,7 @@ pub(crate) fn resolve_method_name( // find the type of the first argument let type_id = arguments - .get(0) + .front() .map(|x| x.return_type) .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Unknown, None)); diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index 1b1d2a858ff..a4023f83e48 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -1142,12 +1142,12 @@ impl<'a> TypeCheckContext<'a> { // When we use a qualified path the expected method should be in trait_methods. None } else { - maybe_method_decl_refs.get(0).cloned() + maybe_method_decl_refs.first().cloned() } } else { // When we can't match any method with parameter types we still return the first method found // This was the behavior before introducing the parameter type matching - matching_method_decl_refs.get(0).cloned() + matching_method_decl_refs.first().cloned() } }; @@ -1156,7 +1156,7 @@ impl<'a> TypeCheckContext<'a> { } if let Some(TypeInfo::ErrorRecovery(err)) = args_buf - .get(0) + .front() .map(|x| (*type_engine.get(x.return_type)).clone()) { Err(err) diff --git a/sway-ir/src/optimize/sroa.rs b/sway-ir/src/optimize/sroa.rs index bce2916be51..99a7d04b8f3 100644 --- a/sway-ir/src/optimize/sroa.rs +++ b/sway-ir/src/optimize/sroa.rs @@ -246,7 +246,7 @@ pub fn sroa( let elm_index_values = indices .iter() .map(|&index| { - let c = Constant::new_uint(context, 64, index.try_into().unwrap()); + let c = Constant::new_uint(context, 64, index.into()); Value::new_constant(context, c) }) .collect(); @@ -316,7 +316,7 @@ pub fn sroa( let elm_index_values = indices .iter() .map(|&index| { - let c = Constant::new_uint(context, 64, index.try_into().unwrap()); + let c = Constant::new_uint(context, 64, index.into()); Value::new_constant(context, c) }) .collect(); diff --git a/sway-lsp/src/core/token.rs b/sway-lsp/src/core/token.rs index 3de7c57cde9..abf794ad8da 100644 --- a/sway-lsp/src/core/token.rs +++ b/sway-lsp/src/core/token.rs @@ -229,7 +229,7 @@ impl std::hash::Hash for TokenIdent { /// Check if the given method is a [core::ops] application desugared from short-hand syntax like / + * - etc. pub fn desugared_op(prefixes: &[Ident]) -> bool { - let prefix0 = prefixes.get(0).map(|ident| ident.as_str()); + let prefix0 = prefixes.first().map(|ident| ident.as_str()); let prefix1 = prefixes.get(1).map(|ident| ident.as_str()); if let (Some("core"), Some("ops")) = (prefix0, prefix1) { return true; diff --git a/sway-parse/src/parser.rs b/sway-parse/src/parser.rs index 0d5a87333fb..721086b7dc4 100644 --- a/sway-parse/src/parser.rs +++ b/sway-parse/src/parser.rs @@ -288,7 +288,7 @@ impl<'a, 'e> Parser<'a, 'e> { /// To calculate lines the original source code needs to be transversed. pub fn consume_while_line_equals(&mut self, line: usize) { loop { - let Some(current_token) = self.token_trees.get(0) else { + let Some(current_token) = self.token_trees.first() else { break; }; @@ -444,7 +444,7 @@ impl<'original, 'a, 'e> ParseRecoveryStrategies<'original, 'a, 'e> { } else { self.last_consumed_token() .map(|x| x.span()) - .or_else(|| self.fork_token_trees.get(0).map(|x| x.span())) + .or_else(|| self.fork_token_trees.first().map(|x| x.span())) .map(|x| x.start_pos().line_col().0) }; @@ -483,7 +483,7 @@ impl<'original, 'a, 'e> ParseRecoveryStrategies<'original, 'a, 'e> { /// This is the last consumed token of the forked parser. This the token /// immediately before the forked parser head. pub fn last_consumed_token(&self) -> Option<&GenericTokenTree> { - let fork_head_span = self.fork_token_trees.get(0)?.span(); + let fork_head_span = self.fork_token_trees.first()?.span(); // find the last token consumed by the fork let original = self.original.borrow(); @@ -504,7 +504,7 @@ impl<'original, 'a, 'e> ParseRecoveryStrategies<'original, 'a, 'e> { let original = self.original.borrow_mut(); // collect all tokens trees that were consumed by the fork - let qty = if let Some(first_fork_tt) = p.token_trees.get(0) { + let qty = if let Some(first_fork_tt) = p.token_trees.first() { original .token_trees .iter() @@ -528,7 +528,7 @@ impl<'original, 'a, 'e> ParseRecoveryStrategies<'original, 'a, 'e> { let mut original = self.original.borrow_mut(); // collect all tokens trees that were consumed by the fork - let qty = if let Some(first_fork_tt) = p.token_trees.get(0) { + let qty = if let Some(first_fork_tt) = p.token_trees.first() { original .token_trees .iter() diff --git a/sway-parse/src/priv_prelude.rs b/sway-parse/src/priv_prelude.rs index 0fab33ecc2d..c11b6858566 100644 --- a/sway-parse/src/priv_prelude.rs +++ b/sway-parse/src/priv_prelude.rs @@ -1,16 +1,5 @@ -pub use { - crate::{ - brackets::ParseBracket, - expr::op_code::parse_instruction, - parse::{Parse, ParseToEnd, Peek}, - parser::{ParseResult, Parser, ParserConsumed, Peeker}, - }, - extension_trait::extension_trait, - num_bigint::BigUint, - std::{ - fmt, marker::PhantomData, mem, ops::ControlFlow, path::PathBuf, str::FromStr, sync::Arc, - }, - sway_types::{Ident, Span, Spanned}, - thiserror::Error, - unicode_xid::UnicodeXID, +pub use crate::{ + brackets::ParseBracket, + parse::{ParseToEnd, Peek}, + parser::{ParseResult, ParserConsumed, Peeker}, }; diff --git a/sway-parse/src/token.rs b/sway-parse/src/token.rs index 1ea53621870..bf307f328fc 100644 --- a/sway-parse/src/token.rs +++ b/sway-parse/src/token.rs @@ -840,8 +840,7 @@ fn error(handler: &Handler, error: LexError) -> ErrorEmitted { #[cfg(test)] mod tests { - use super::{lex, lex_commented}; - use crate::priv_prelude::*; + use super::*; use assert_matches::assert_matches; use std::sync::Arc; use sway_ast::{ diff --git a/test/src/sdk-harness/test_projects/auth/mod.rs b/test/src/sdk-harness/test_projects/auth/mod.rs index 0bad6d9a3ad..f12bf989383 100644 --- a/test/src/sdk-harness/test_projects/auth/mod.rs +++ b/test/src/sdk-harness/test_projects/auth/mod.rs @@ -1,5 +1,8 @@ use fuels::{ - accounts::{wallet::{Wallet, WalletUnlocked}, predicate::Predicate}, + accounts::{ + predicate::Predicate, + wallet::{Wallet, WalletUnlocked}, + }, prelude::*, types::ContractId, }; @@ -15,7 +18,7 @@ abigen!( abi = "test_artifacts/auth_caller_contract/out/debug/auth_caller_contract-abi.json" ), Predicate( - name = "AuthPredicate", + name = "AuthPredicate", abi = "test_artifacts/auth_predicate/out/debug/auth_predicate-abi.json" ), ); @@ -112,27 +115,37 @@ async fn can_get_predicate_id() { coin_amount: 1_000, }], ); - let wallets = &launch_custom_provider_and_get_wallets(wallets_config, None, None).await.unwrap(); + let wallets = &launch_custom_provider_and_get_wallets(wallets_config, None, None) + .await + .unwrap(); let first_wallet = &wallets[0]; let second_wallet = &wallets[1]; // Setup Predciate - let hex_predicate_address: &str = "0x76bae6a88c3f54a9aee40ee5390696dd9edaf1b2a16d96a75adbcaac2ec6584f"; - let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string"); + let hex_predicate_address: &str = + "0x76bae6a88c3f54a9aee40ee5390696dd9edaf1b2a16d96a75adbcaac2ec6584f"; + let predicate_address = + Address::from_str(hex_predicate_address).expect("failed to create Address from string"); let predicate_bech32_address = Bech32Address::from(predicate_address); let predicate_data = AuthPredicateEncoder::encode_data(predicate_bech32_address); - let predicate: Predicate = Predicate::load_from("test_artifacts/auth_predicate/out/debug/auth_predicate.bin").unwrap() - .with_provider(first_wallet.try_provider().unwrap().clone()) - .with_data(predicate_data); + let predicate: Predicate = + Predicate::load_from("test_artifacts/auth_predicate/out/debug/auth_predicate.bin") + .unwrap() + .with_provider(first_wallet.try_provider().unwrap().clone()) + .with_data(predicate_data); // Next, we lock some assets in this predicate using the first wallet: // First wallet transfers amount to predicate. first_wallet .transfer(predicate.address(), 500, asset_id, TxPolicies::default()) - .await.unwrap(); + .await + .unwrap(); // Check predicate balance. - let balance = predicate.get_asset_balance(&AssetId::default()).await.unwrap(); + let balance = predicate + .get_asset_balance(&AssetId::default()) + .await + .unwrap(); assert_eq!(balance, 500); // Then we can transfer assets owned by the predicate via the Account trait: @@ -146,14 +159,21 @@ async fn can_get_predicate_id() { asset_id, TxPolicies::default(), ) - .await.unwrap(); + .await + .unwrap(); // Predicate balance is zero. - let balance = predicate.get_asset_balance(&AssetId::default()).await.unwrap(); + let balance = predicate + .get_asset_balance(&AssetId::default()) + .await + .unwrap(); assert_eq!(balance, 0); // Second wallet balance is updated. - let balance = second_wallet.get_asset_balance(&AssetId::default()).await.unwrap(); + let balance = second_wallet + .get_asset_balance(&AssetId::default()) + .await + .unwrap(); assert_eq!(balance, 1500); } @@ -170,26 +190,36 @@ async fn when_incorrect_predicate_address_passed() { coin_amount: 1_000, }], ); - let wallets = &launch_custom_provider_and_get_wallets(wallets_config, None, None).await.unwrap(); + let wallets = &launch_custom_provider_and_get_wallets(wallets_config, None, None) + .await + .unwrap(); let first_wallet = &wallets[0]; let second_wallet = &wallets[1]; // Setup Predciate with incorrect address - let hex_predicate_address: &str = "0x36bf4bd40f2a3b3db595ef8fd8b21dbe9e6c0dd7b419b4413ff6b584ce7da5d7"; - let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string"); + let hex_predicate_address: &str = + "0x36bf4bd40f2a3b3db595ef8fd8b21dbe9e6c0dd7b419b4413ff6b584ce7da5d7"; + let predicate_address = + Address::from_str(hex_predicate_address).expect("failed to create Address from string"); let predicate_data = AuthPredicateEncoder::encode_data(Bech32Address::from(predicate_address)); - let predicate: Predicate = Predicate::load_from("test_artifacts/auth_predicate/out/debug/auth_predicate.bin").unwrap() - .with_provider(first_wallet.try_provider().unwrap().clone()) - .with_data(predicate_data); + let predicate: Predicate = + Predicate::load_from("test_artifacts/auth_predicate/out/debug/auth_predicate.bin") + .unwrap() + .with_provider(first_wallet.try_provider().unwrap().clone()) + .with_data(predicate_data); // Next, we lock some assets in this predicate using the first wallet: // First wallet transfers amount to predicate. first_wallet .transfer(predicate.address(), 500, asset_id, TxPolicies::default()) - .await.unwrap(); + .await + .unwrap(); // Check predicate balance. - let balance = predicate.get_asset_balance(&AssetId::default()).await.unwrap(); + let balance = predicate + .get_asset_balance(&AssetId::default()) + .await + .unwrap(); assert_eq!(balance, 500); // Then we can transfer assets owned by the predicate via the Account trait: @@ -203,5 +233,6 @@ async fn when_incorrect_predicate_address_passed() { asset_id, TxPolicies::default(), ) - .await.unwrap(); + .await + .unwrap(); } diff --git a/test/src/sdk-harness/test_projects/low_level_call/mod.rs b/test/src/sdk-harness/test_projects/low_level_call/mod.rs index d67ca65068a..d91cb6f8208 100644 --- a/test/src/sdk-harness/test_projects/low_level_call/mod.rs +++ b/test/src/sdk-harness/test_projects/low_level_call/mod.rs @@ -22,7 +22,8 @@ macro_rules! calldata { abigen!( Contract( name = "TestContract", - abi = "test_artifacts/low_level_callee_contract/out/debug/low_level_callee_contract-abi.json" + abi = + "test_artifacts/low_level_callee_contract/out/debug/low_level_callee_contract-abi.json" ), Script( name = "TestScript", diff --git a/test/src/sdk-harness/test_projects/low_level_call_bytes/mod.rs b/test/src/sdk-harness/test_projects/low_level_call_bytes/mod.rs index e9b1cc30489..301bb28ac2a 100644 --- a/test/src/sdk-harness/test_projects/low_level_call_bytes/mod.rs +++ b/test/src/sdk-harness/test_projects/low_level_call_bytes/mod.rs @@ -22,7 +22,8 @@ macro_rules! calldata { abigen!( Contract( name = "TestContract", - abi = "test_artifacts/low_level_callee_contract/out/debug/low_level_callee_contract-abi.json" + abi = + "test_artifacts/low_level_callee_contract/out/debug/low_level_callee_contract-abi.json" ), Script( name = "TestScript", diff --git a/test/src/sdk-harness/test_projects/storage_access/mod.rs b/test/src/sdk-harness/test_projects/storage_access/mod.rs index 0a988da76f4..4130c53fdca 100644 --- a/test/src/sdk-harness/test_projects/storage_access/mod.rs +++ b/test/src/sdk-harness/test_projects/storage_access/mod.rs @@ -168,13 +168,7 @@ async fn maps_in_struct_access() { async fn clears_storage_key() { let methods = test_storage_access_instance().await.methods(); - assert_eq!( - methods - .clears_storage_key() - .call() - .await - .unwrap() - .value, - true + assert!( + methods.clears_storage_key().call().await.unwrap().value ); } diff --git a/test/src/sdk-harness/test_projects/tx_fields/mod.rs b/test/src/sdk-harness/test_projects/tx_fields/mod.rs index c8455982e62..b60783123df 100644 --- a/test/src/sdk-harness/test_projects/tx_fields/mod.rs +++ b/test/src/sdk-harness/test_projects/tx_fields/mod.rs @@ -187,10 +187,9 @@ async fn setup_output_predicate() -> (WalletUnlocked, WalletUnlocked, Predicate, } mod tx { - use fuel_vm::fuel_tx::field::Script; - use fuels::types::coin_type::CoinType; - use super::*; + use fuel_vm::fuel_tx::field::Script; + use fuels::types::{coin_type::CoinType, transaction::Transaction}; #[tokio::test] async fn can_get_tx_type() {