From ada30387e1d98720727f24b6a73ad6d21895d773 Mon Sep 17 00:00:00 2001 From: saimeunt Date: Tue, 25 Mar 2025 23:18:07 +0100 Subject: [PATCH 1/2] Fix #6727 --- Cargo.lock | 1 + sway-core/Cargo.toml | 1 + .../to_parsed_lang/convert_parse_tree.rs | 30 +++++++++++++++---- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e072a49c916..b8183a0db75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7926,6 +7926,7 @@ dependencies = [ "indexmap 2.7.1", "itertools 0.13.0", "lazy_static", + "num-bigint", "object", "parking_lot", "paste", diff --git a/sway-core/Cargo.toml b/sway-core/Cargo.toml index c6f7f0dfe40..3730e734989 100644 --- a/sway-core/Cargo.toml +++ b/sway-core/Cargo.toml @@ -25,6 +25,7 @@ im.workspace = true indexmap = { workspace = true, features = ["serde"] } itertools.workspace = true lazy_static.workspace = true +num-bigint.workspace = true object = { workspace = true, features = ["write"] } parking_lot.workspace = true paste.workspace = true 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 947e720cddd..8ba852c1c39 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 @@ -13,6 +13,7 @@ use crate::{ }; use either::Either; use itertools::Itertools; +use num_bigint::BigUint; use sway_ast::{ assignable::ElementAccess, expr::{LoopControlFlow, ReassignmentOp, ReassignmentOpVariant}, @@ -3528,12 +3529,27 @@ fn literal_to_literal( } = lit_int; match ty_opt { None => { - let orig_str = span.as_str(); - if let Some(hex_digits) = orig_str.strip_prefix("0x") { - let num_digits = hex_digits.chars().filter(|c| *c != '_').count(); + let mut stripped_str = span.as_str(); + if let Some(stripped) = stripped_str.strip_suffix("b256") { + for (prefix, required_digits) in [("0x", 64), ("0b", 256)] { + if let Some(digits) = stripped.strip_prefix(prefix) { + let num_digits = digits.chars().filter(|c| *c != '_').count(); + if num_digits == required_digits { + stripped_str = stripped; + break; + } + } + } + } + if let Some(hex_digits) = stripped_str.strip_prefix("0x") { + let hex_digits_filtered = hex_digits.replace("_", ""); + let num_digits = hex_digits_filtered.len(); match num_digits { 1..=16 => Literal::Numeric(u64::try_from(parsed).unwrap()), 64 => { + let parsed = + BigUint::parse_bytes(hex_digits_filtered.as_bytes(), 16) + .unwrap(); let bytes = parsed.to_bytes_be(); let mut full_bytes = [0u8; 32]; full_bytes[(32 - bytes.len())..].copy_from_slice(&bytes); @@ -3544,11 +3560,15 @@ fn literal_to_literal( return Err(handler.emit_err(error.into())); } } - } else if let Some(bin_digits) = orig_str.strip_prefix("0b") { - let num_digits = bin_digits.chars().filter(|c| *c != '_').count(); + } else if let Some(bin_digits) = stripped_str.strip_prefix("0b") { + let bin_digits_filtered = bin_digits.replace("_", ""); + let num_digits = bin_digits_filtered.len(); match num_digits { 1..=64 => Literal::Numeric(u64::try_from(parsed).unwrap()), 256 => { + let parsed = + BigUint::parse_bytes(bin_digits_filtered.as_bytes(), 2) + .unwrap(); let bytes = parsed.to_bytes_be(); let mut full_bytes = [0u8; 32]; full_bytes[(32 - bytes.len())..].copy_from_slice(&bytes); From c3e10ae33c56e0354b0454371c3813cd69e9a703 Mon Sep 17 00:00:00 2001 From: saimeunt Date: Thu, 27 Mar 2025 14:48:25 +0100 Subject: [PATCH 2/2] fix b256 literals --- Cargo.lock | 1 - sway-ast/src/literal.rs | 2 ++ sway-core/Cargo.toml | 1 - .../to_parsed_lang/convert_parse_tree.rs | 36 ++++++------------- sway-parse/src/token.rs | 6 ++++ swayfmt/src/utils/language/literal.rs | 1 + .../language/b256_literals/Forc.lock | 8 +++++ .../language/b256_literals/Forc.toml | 9 +++++ .../b256_literals/json_abi_oracle.json | 25 +++++++++++++ .../json_abi_oracle_new_encoding.json | 23 ++++++++++++ .../language/b256_literals/src/main.sw | 19 ++++++++++ .../language/b256_literals/test.toml | 4 +++ 12 files changed, 108 insertions(+), 27 deletions(-) create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/Forc.lock create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/Forc.toml create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/json_abi_oracle.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/json_abi_oracle_new_encoding.json create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/src/main.sw create mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/test.toml diff --git a/Cargo.lock b/Cargo.lock index b8183a0db75..e072a49c916 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7926,7 +7926,6 @@ dependencies = [ "indexmap 2.7.1", "itertools 0.13.0", "lazy_static", - "num-bigint", "object", "parking_lot", "paste", diff --git a/sway-ast/src/literal.rs b/sway-ast/src/literal.rs index 9a07113a91a..a4d111e607d 100644 --- a/sway-ast/src/literal.rs +++ b/sway-ast/src/literal.rs @@ -42,6 +42,7 @@ pub enum LitIntType { I16, I32, I64, + B256, } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] @@ -97,6 +98,7 @@ impl Literal { LitIntType::I16 => "i16", LitIntType::I32 => "i32", LitIntType::I64 => "i64", + LitIntType::B256 => "b256", }) } } diff --git a/sway-core/Cargo.toml b/sway-core/Cargo.toml index 3730e734989..c6f7f0dfe40 100644 --- a/sway-core/Cargo.toml +++ b/sway-core/Cargo.toml @@ -25,7 +25,6 @@ im.workspace = true indexmap = { workspace = true, features = ["serde"] } itertools.workspace = true lazy_static.workspace = true -num-bigint.workspace = true object = { workspace = true, features = ["write"] } parking_lot.workspace = true paste.workspace = true 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 8ba852c1c39..7b442a575fb 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 @@ -13,7 +13,6 @@ use crate::{ }; use either::Either; use itertools::Itertools; -use num_bigint::BigUint; use sway_ast::{ assignable::ElementAccess, expr::{LoopControlFlow, ReassignmentOp, ReassignmentOpVariant}, @@ -3529,27 +3528,12 @@ fn literal_to_literal( } = lit_int; match ty_opt { None => { - let mut stripped_str = span.as_str(); - if let Some(stripped) = stripped_str.strip_suffix("b256") { - for (prefix, required_digits) in [("0x", 64), ("0b", 256)] { - if let Some(digits) = stripped.strip_prefix(prefix) { - let num_digits = digits.chars().filter(|c| *c != '_').count(); - if num_digits == required_digits { - stripped_str = stripped; - break; - } - } - } - } - if let Some(hex_digits) = stripped_str.strip_prefix("0x") { - let hex_digits_filtered = hex_digits.replace("_", ""); - let num_digits = hex_digits_filtered.len(); + let orig_str = span.as_str(); + if let Some(hex_digits) = orig_str.strip_prefix("0x") { + let num_digits = hex_digits.chars().filter(|c| *c != '_').count(); match num_digits { 1..=16 => Literal::Numeric(u64::try_from(parsed).unwrap()), 64 => { - let parsed = - BigUint::parse_bytes(hex_digits_filtered.as_bytes(), 16) - .unwrap(); let bytes = parsed.to_bytes_be(); let mut full_bytes = [0u8; 32]; full_bytes[(32 - bytes.len())..].copy_from_slice(&bytes); @@ -3560,15 +3544,11 @@ fn literal_to_literal( return Err(handler.emit_err(error.into())); } } - } else if let Some(bin_digits) = stripped_str.strip_prefix("0b") { - let bin_digits_filtered = bin_digits.replace("_", ""); - let num_digits = bin_digits_filtered.len(); + } else if let Some(bin_digits) = orig_str.strip_prefix("0b") { + let num_digits = bin_digits.chars().filter(|c| *c != '_').count(); match num_digits { 1..=64 => Literal::Numeric(u64::try_from(parsed).unwrap()), 256 => { - let parsed = - BigUint::parse_bytes(bin_digits_filtered.as_bytes(), 2) - .unwrap(); let bytes = parsed.to_bytes_be(); let mut full_bytes = [0u8; 32]; full_bytes[(32 - bytes.len())..].copy_from_slice(&bytes); @@ -3635,6 +3615,12 @@ fn literal_to_literal( let error = ConvertParseTreeError::SignedIntegersNotSupported { span }; return Err(handler.emit_err(error.into())); } + LitIntType::B256 => { + let bytes = parsed.to_bytes_be(); + let mut full_bytes = [0u8; 32]; + full_bytes[(32 - bytes.len())..].copy_from_slice(&bytes); + Literal::B256(full_bytes) + } }, } } diff --git a/sway-parse/src/token.rs b/sway-parse/src/token.rs index cafa522a132..f6d411c8247 100644 --- a/sway-parse/src/token.rs +++ b/sway-parse/src/token.rs @@ -759,11 +759,13 @@ pub fn parse_int_suffix(suffix: &str) -> Option { "i16" => LitIntType::I16, "i32" => LitIntType::I32, "i64" => LitIntType::I64, + "b256" => LitIntType::B256, _ => return None, }) } fn parse_digits(big_uint: &mut BigUint, l: &mut Lexer<'_>, radix: u32) -> Option { + let mut num_digits = 1; loop { match l.stream.peek() { None => break None, @@ -773,9 +775,13 @@ fn parse_digits(big_uint: &mut BigUint, l: &mut Lexer<'_>, radix: u32) -> Option Some(&(index, character)) => match character.to_digit(radix) { None => break Some(index), Some(digit) => { + if (radix == 16 && num_digits == 64) || (radix == 2 && num_digits == 256) { + break Some(index); + } let _ = l.stream.next(); *big_uint *= radix; *big_uint += digit; + num_digits += 1; } }, }; diff --git a/swayfmt/src/utils/language/literal.rs b/swayfmt/src/utils/language/literal.rs index a2530204d15..d78c5f881a8 100644 --- a/swayfmt/src/utils/language/literal.rs +++ b/swayfmt/src/utils/language/literal.rs @@ -57,6 +57,7 @@ impl Format for Literal { LitIntType::I16 => "_i16", LitIntType::I32 => "_i32", LitIntType::I64 => "_i64", + LitIntType::B256 => "_b256", }; write!(formatted_code, "{}", int_type)?; } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/Forc.lock new file mode 100644 index 00000000000..7ada6badf0c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "b256_literals" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-CB876055E4BB3A9C" diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/Forc.toml new file mode 100644 index 00000000000..f4412cb1547 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +implicit-std = false +license = "Apache-2.0" +name = "b256_literals" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/json_abi_oracle.json new file mode 100644 index 00000000000..03b2f150939 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/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": "bool", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/json_abi_oracle_new_encoding.json new file mode 100644 index 00000000000..668a88f2e07 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/json_abi_oracle_new_encoding.json @@ -0,0 +1,23 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "type": "bool" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + } + ], + "loggedTypes": [], + "messagesTypes": [], + "metadataTypes": [], + "programType": "script", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/src/main.sw new file mode 100644 index 00000000000..83b67bc799b --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/src/main.sw @@ -0,0 +1,19 @@ +script; + +fn main() -> bool { + // Hex + let _x = 0x0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000b256; + assert(_x == b256::zero()); + + let _x = 0x0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_b256; + assert(_x.as_u256() == 0xb256); + + // Binary + let _y = 0b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000b256; + assert(_y == b256::zero()); + + let _y = 0b0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_1011_0010_0101_0110; + assert(_y.as_u256() == 0xb256); + + true +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/test.toml new file mode 100644 index 00000000000..53fb5ce9a94 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/b256_literals/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 1 } +expected_result_new_encoding = { action = "return_data", value = "01" } +validate_abi = true