diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b732b6ba2c7..e0063163659 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: @@ -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/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/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/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..63a661b9725 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,14 +15,29 @@ 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 { - let cmd = args.get(0).expect("`args` must not be empty"); +pub(crate) fn execute_external_subcommand( + args: Vec, + silent: bool, +) -> Result { + let cmd = args.first().expect("`args` must not be empty"); let args = &args[1..]; let path = find_external_subcommand(cmd); let command = match path { Some(command) => 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()) 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/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-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/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/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/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/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/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/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/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..cc4d22432c1 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), } } } @@ -765,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 = @@ -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/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 8ddab8661df..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 @@ -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, @@ -2104,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::*; @@ -2294,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/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..a4023f83e48 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, }; @@ -1122,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() } }; @@ -1136,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-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/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..abc69cb7e58 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(), } } @@ -267,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(..) @@ -320,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 { .. } @@ -364,8 +360,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(); @@ -373,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 @@ -386,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 94912dd5aed..66067478781 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, } @@ -183,6 +184,7 @@ pub enum TypeInfo { name: Ident, trait_type_id: TypeId, }, + Ref(TypeArgument), } impl HashWithEngines for TypeInfo { @@ -261,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 @@ -333,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), ( @@ -351,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 }) => { @@ -370,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 { @@ -385,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(), } } @@ -500,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()), } @@ -574,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}") } @@ -674,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}") } @@ -711,6 +736,7 @@ impl TypeInfo { TypeInfo::Slice(..) => 22, TypeInfo::StringSlice => 23, TypeInfo::TraitType { .. } => 24, + TypeInfo::Ref { .. } => 25, } } @@ -917,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(), @@ -1032,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. @@ -1043,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() } @@ -1055,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, @@ -1100,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(_, _) @@ -1109,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, @@ -1147,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, @@ -1184,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 { .. } @@ -1197,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`. /// @@ -1205,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( @@ -1263,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(), @@ -1289,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 @@ -1304,7 +1345,8 @@ impl TypeInfo { | TypeInfo::Numeric | TypeInfo::Placeholder(_) | TypeInfo::TypeParam(_) - | TypeInfo::Alias { .. } => true, + | TypeInfo::Alias { .. } + | TypeInfo::Ref(_) => true, } } @@ -1320,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: @@ -1335,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, @@ -1364,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 @@ -1378,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, @@ -1405,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: @@ -1419,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 fcdb4b2cc73..eaf31f21900 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, }, ); @@ -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 c0baf598058..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(), } } } @@ -1138,89 +1140,118 @@ 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 { - 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.") - ), - ]; + 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; // 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}\" ")) + ) + )), + } + + 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}")); + 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. 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/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-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-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 d345e303bc7..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}; - +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,10 +55,44 @@ 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); 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/auth.sw b/sway-lib-std/src/auth.sw index 4a38eafd4bb..8c2812a2fdc 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.") @@ -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/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 31bcad2645d..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; @@ -195,14 +194,238 @@ 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); + 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); -} \ No newline at end of file + + // 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); +} 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/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/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 da01bba6edd..c0e36f553f4 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); + } +} 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-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/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/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/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..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 } => { @@ -748,6 +751,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: _, @@ -1062,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/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/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/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/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_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 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/stdlib/logarithmic_test/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/json_abi_oracle.json similarity index 94% rename from test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/json_abi_oracle.json rename to test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_control_flow_expressions/json_abi_oracle.json index 03b2f150939..ad50b55d54c 100644 --- 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/language/references/dereferencing_control_flow_expressions/json_abi_oracle.json @@ -17,7 +17,7 @@ "types": [ { "components": null, - "type": "bool", + "type": "u64", "typeId": 0, "typeParameters": null } 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/stdlib/exponentiation_test/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/json_abi_oracle.json similarity index 94% rename from test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/json_abi_oracle.json rename to test/src/e2e_vm_tests/test_programs/should_pass/language/references/dereferencing_operator_star/json_abi_oracle.json index 03b2f150939..ad50b55d54c 100644 --- 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/language/references/dereferencing_operator_star/json_abi_oracle.json @@ -17,7 +17,7 @@ "types": [ { "components": null, - "type": "bool", + "type": "u64", "typeId": 0, "typeParameters": null } 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 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/logarithmic_test/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/Forc.toml similarity index 86% rename from test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/Forc.toml rename to test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/Forc.toml index 19fdea555c6..ab0d51c34f9 100644 --- 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/assert_ne/Forc.toml @@ -2,7 +2,7 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -name = "logarithmic_test" +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/exponentiation_test/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/test.toml similarity index 100% rename from test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/test.toml rename to test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne/test.toml 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/exponentiation_test/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/Forc.toml similarity index 57% rename from test/src/e2e_vm_tests/test_programs/should_pass/stdlib/exponentiation_test/Forc.toml rename to test/src/e2e_vm_tests/test_programs/should_pass/stdlib/assert_ne_revert/Forc.toml index 7e0f76dc98f..19c5cda08d2 100644 --- 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/assert_ne_revert/Forc.toml @@ -2,7 +2,7 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -name = "exponentiation_test" +name = "assert_ne_revert" [dependencies] -std = { path = "../../../../../../../sway-lib-std" } +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 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/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/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/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 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/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/.gitignore b/test/src/sdk-harness/test_artifacts/auth_predicate/.gitignore similarity index 100% rename from test/src/e2e_vm_tests/test_programs/should_pass/stdlib/logarithmic_test/.gitignore rename to test/src/sdk-harness/test_artifacts/auth_predicate/.gitignore 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..f12bf989383 100644 --- a/test/src/sdk-harness/test_projects/auth/mod.rs +++ b/test/src/sdk-harness/test_projects/auth/mod.rs @@ -1,8 +1,12 @@ use fuels::{ - accounts::wallet::{Wallet, WalletUnlocked}, + accounts::{ + predicate::Predicate, + wallet::{Wallet, WalletUnlocked}, + }, prelude::*, types::ContractId, }; +use std::str::FromStr; abigen!( Contract( @@ -12,7 +16,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 +102,137 @@ 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(); +} 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() {