From da0caf9ff023751e2a2b4a687e1271b23563d309 Mon Sep 17 00:00:00 2001 From: Daniel Frederico Lins Leite Date: Mon, 5 Aug 2024 08:52:04 +0100 Subject: [PATCH 1/2] Support for slice new syntax &[T] (#6307) ## Description Part of https://github.com/FuelLabs/sway/issues/5110. This PR implements supports for the slice new syntax: `&[T]`. The old syntax is still supported and will be deprecated in a future PR. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers. --- sway-ast/src/ty/mod.rs | 9 ++- sway-parse/src/item/item_impl.rs | 26 ++++++-- sway-parse/src/parser.rs | 34 ++++++++-- sway-parse/src/test_utils.rs | 25 +++++--- sway-parse/src/ty/mod.rs | 63 ++++++++++++++----- swayfmt/src/utils/language/ty.rs | 25 +++++--- .../aliases/json_abi_oracle_new_encoding.json | 0 .../json_abi_oracle_new_encoding.json | 0 .../json_abi_oracle_new_encoding.json | 0 .../json_abi_oracle_new_encoding.json | 0 .../json_abi_oracle_new_encoding.json | 0 .../json_abi_oracle_new_encoding.json | 0 .../json_abi_oracle_new_encoding.json | 0 13 files changed, 139 insertions(+), 43 deletions(-) mode change 100755 => 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/aliases/json_abi_oracle_new_encoding.json mode change 100755 => 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/multiple_imports_of_same_reexport/json_abi_oracle_new_encoding.json mode change 100755 => 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/reexport_paths/json_abi_oracle_new_encoding.json mode change 100755 => 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/shadowing_in_reexporting_module/json_abi_oracle_new_encoding.json mode change 100755 => 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_glob_import/json_abi_oracle_new_encoding.json mode change 100755 => 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_item_import/json_abi_oracle_new_encoding.json mode change 100755 => 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/visibility/json_abi_oracle_new_encoding.json diff --git a/sway-ast/src/ty/mod.rs b/sway-ast/src/ty/mod.rs index 3973a276372..7e2bbc35cab 100644 --- a/sway-ast/src/ty/mod.rs +++ b/sway-ast/src/ty/mod.rs @@ -19,7 +19,7 @@ pub enum Ty { ty: SquareBrackets>, }, Slice { - slice_token: SliceToken, + slice_token: Option, ty: SquareBrackets>, }, Ref { @@ -42,7 +42,12 @@ impl Spanned for Ty { Ty::StringArray { str_token, length } => Span::join(str_token.span(), &length.span()), 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::Slice { slice_token, ty } => { + let span = slice_token + .as_ref() + .map(|s| Span::join(s.span(), &ty.span())); + span.unwrap_or_else(|| ty.span()) + } Ty::Ref { ampersand_token, mut_token: _, diff --git a/sway-parse/src/item/item_impl.rs b/sway-parse/src/item/item_impl.rs index 3894045f264..7dc51e86fce 100644 --- a/sway-parse/src/item/item_impl.rs +++ b/sway-parse/src/item/item_impl.rs @@ -88,12 +88,28 @@ mod tests { #[test] fn parse_impl_slice() { - let item = parse::( - r#" - impl __slice[T] {} - "#, + // deprecated syntax + let item = parse::("impl __slice[T] {}"); + assert_matches!( + item.ty, + Ty::Slice { + slice_token: Some(..), + ty: _ + } ); - assert_matches!(item.ty, Ty::Slice { .. }); + + // "new" syntax + let item = parse::("impl [T] {}"); + assert_matches!( + item.ty, + Ty::Slice { + slice_token: None, + ty: _ + } + ); + + let item = parse::("impl &[T] {}"); + assert_matches!(item.ty, Ty::Ref { ty, .. } if matches!(&*ty, Ty::Slice { .. })); } #[test] diff --git a/sway-parse/src/parser.rs b/sway-parse/src/parser.rs index ad9d3e7ffc2..804ead365b3 100644 --- a/sway-parse/src/parser.rs +++ b/sway-parse/src/parser.rs @@ -207,6 +207,18 @@ impl<'a, 'e> Parser<'a, 'e> { r } + /// This method is useful if `T` does not impl `ParseToEnd` + pub fn try_parse_and_check_empty( + mut self, + append_diagnostics: bool, + ) -> ParseResult)>> { + let value = self.try_parse(append_diagnostics)?; + match self.check_empty() { + Some(consumed) => Ok(Some((value, consumed))), + None => Ok(None), + } + } + /// Parses a `T` in its canonical way. pub fn parse(&mut self) -> ParseResult { T::parse(self) @@ -223,13 +235,23 @@ impl<'a, 'e> Parser<'a, 'e> { T::parse_to_end(self) } - pub fn try_parse_to_end(mut self) -> ParseResult)>> { - let value = self.parse()?; - let consumed = match self.check_empty() { - Some(consumed) => consumed, - None => return Ok(None), + /// Do not advance the parser on failure + pub fn try_parse_to_end( + &mut self, + append_diagnostics: bool, + ) -> ParseResult<(T, ParserConsumed<'a>)> { + let handler = Handler::default(); + let fork = Parser { + token_trees: self.token_trees, + full_span: self.full_span.clone(), + handler: &handler, + check_double_underscore: self.check_double_underscore, }; - Ok(Some((value, consumed))) + let r = T::parse_to_end(fork); + if append_diagnostics { + self.handler.append(handler); + } + r } pub fn enter_delimited( diff --git a/sway-parse/src/test_utils.rs b/sway-parse/src/test_utils.rs index b0ceef2cbe4..976d2a4a958 100644 --- a/sway-parse/src/test_utils.rs +++ b/sway-parse/src/test_utils.rs @@ -1,3 +1,5 @@ +use sway_error::handler::Handler; + use crate::{priv_prelude::ParseToEnd, Parse, Parser}; use std::sync::Arc; @@ -5,11 +7,15 @@ pub fn parse(input: &str) -> T where T: Parse, { - let handler = <_>::default(); + let handler = Handler::default(); let ts = crate::token::lex(&handler, &Arc::from(input), 0, input.len(), None).unwrap(); - Parser::new(&handler, &ts) - .parse() - .unwrap_or_else(|_| panic!("Parse error: {:?}", handler.consume().0)) + let r = Parser::new(&handler, &ts).parse(); + + if handler.has_errors() || handler.has_warnings() { + panic!("{:?}", handler.consume()); + } + + r.unwrap_or_else(|_| panic!("Parse error: {:?}", handler.consume().0)) } pub fn parse_to_end(input: &str) -> T @@ -18,8 +24,11 @@ where { let handler = <_>::default(); let ts = crate::token::lex(&handler, &Arc::from(input), 0, input.len(), None).unwrap(); - Parser::new(&handler, &ts) - .parse_to_end() - .map(|(m, _)| m) - .unwrap_or_else(|_| panic!("Parse error: {:?}", handler.consume().0)) + let r = Parser::new(&handler, &ts).parse_to_end().map(|(m, _)| m); + + if handler.has_errors() || handler.has_warnings() { + panic!("{:?}", handler.consume()); + } + + r.unwrap_or_else(|_| panic!("Parse error: {:?}", handler.consume().0)) } diff --git a/sway-parse/src/ty/mod.rs b/sway-parse/src/ty/mod.rs index dcba9b74ef1..b01153da595 100644 --- a/sway-parse/src/ty/mod.rs +++ b/sway-parse/src/ty/mod.rs @@ -1,7 +1,6 @@ use crate::{Parse, ParseBracket, ParseResult, ParseToEnd, Parser, ParserConsumed}; - use sway_ast::brackets::{Parens, SquareBrackets}; -use sway_ast::keywords::{DoubleColonToken, OpenAngleBracketToken}; +use sway_ast::keywords::{DoubleColonToken, OpenAngleBracketToken, PtrToken, SliceToken}; use sway_ast::ty::{Ty, TyArrayDescriptor, TyTupleDescriptor}; use sway_error::parser_error::ParseErrorKind; use sway_types::{ast::Delimiter, Ident}; @@ -30,9 +29,24 @@ impl Parse for Ty { return Err(parser .emit_error(ParseErrorKind::ExpectedCommaOrCloseParenInTupleOrParenExpression)); } - if let Some(descriptor) = SquareBrackets::try_parse(parser)? { - return Ok(Ty::Array(descriptor)); - }; + + if let Some((mut inner_parser, span)) = parser.enter_delimited(Delimiter::Bracket) { + // array like [type; len] + if let Ok((array, _)) = inner_parser.try_parse_to_end::(false) { + return Ok(Ty::Array(SquareBrackets { inner: array, span })); + } + + // slice like [type] + if let Ok(Some((ty, _))) = inner_parser.try_parse_and_check_empty::(false) { + return Ok(Ty::Slice { + slice_token: None, + ty: SquareBrackets { + inner: Box::new(ty), + span, + }, + }); + } + } if let Some(str_token) = parser.take() { let length = SquareBrackets::try_parse_all_inner(parser, |mut parser| { @@ -48,18 +62,26 @@ impl Parse for Ty { if let Some(underscore_token) = parser.take() { return Ok(Ty::Infer { underscore_token }); } - if let Some(ptr_token) = parser.take() { + + if let Some(ptr_token) = parser.take::() { let ty = SquareBrackets::parse_all_inner(parser, |mut parser| { parser.emit_error(ParseErrorKind::UnexpectedTokenAfterPtrType) })?; return Ok(Ty::Ptr { ptr_token, ty }); } - if let Some(slice_token) = parser.take() { - let ty = SquareBrackets::parse_all_inner(parser, |mut parser| { + + // slice like __slice[type] + // TODO: deprecate this syntax (see https://github.com/FuelLabs/sway/issues/5110) + if let Some(slice_token) = parser.take::() { + let ty = SquareBrackets::>::parse_all_inner(parser, |mut parser| { parser.emit_error(ParseErrorKind::UnexpectedTokenAfterSliceType) })?; - return Ok(Ty::Slice { slice_token, ty }); + return Ok(Ty::Slice { + slice_token: Some(slice_token), + ty, + }); } + if let Some(ampersand_token) = parser.take() { let mut_token = parser.take(); let ty = Box::new(parser.parse()?); @@ -69,9 +91,11 @@ impl Parse for Ty { ty, }); } + if let Some(bang_token) = parser.take() { return Ok(Ty::Never { bang_token }); } + if parser.peek::().is_some() || parser.peek::().is_some() || parser.peek::().is_some() @@ -79,6 +103,7 @@ impl Parse for Ty { let path_type = parser.parse()?; return Ok(Ty::Path(path_type)); } + Err(parser.emit_error(ParseErrorKind::ExpectedType)) } } @@ -121,14 +146,24 @@ mod tests { assert_matches!(item, Ty::Ptr { .. }); } + #[test] + fn parse_array() { + let item = parse::("[T; 1]"); + assert_matches!(item, Ty::Array { .. }); + } + #[test] fn parse_slice() { - let item = parse::( - r#" - __slice[T] - "#, - ); + // deprecated syntax + let item = parse::("__slice[T]"); assert_matches!(item, Ty::Slice { .. }); + + // " new" syntax + let item = parse::("[T]"); + assert_matches!(item, Ty::Slice { .. }); + + let item = parse::("&[T]"); + assert_matches!(item, Ty::Ref { ty, .. } if matches!(&*ty, Ty::Slice { .. })); } #[test] diff --git a/swayfmt/src/utils/language/ty.rs b/swayfmt/src/utils/language/ty.rs index 1d764e83bd7..a509cca1567 100644 --- a/swayfmt/src/utils/language/ty.rs +++ b/swayfmt/src/utils/language/ty.rs @@ -117,15 +117,20 @@ fn format_ptr( fn format_slice( formatted_code: &mut FormattedCode, - slice_token: SliceToken, + slice_token: Option, ty: SquareBrackets>, ) -> Result<(), FormatterError> { - write!( - formatted_code, - "{}[{}]", - slice_token.span().as_str(), - ty.into_inner().span().as_str() - )?; + if let Some(slice_token) = slice_token { + write!( + formatted_code, + "{}[{}]", + slice_token.span().as_str(), + ty.into_inner().span().as_str() + )?; + } else { + write!(formatted_code, "[{}]", ty.into_inner().span().as_str())?; + } + Ok(()) } @@ -202,7 +207,11 @@ impl LeafSpans for Ty { collected_spans } Ty::Slice { slice_token, ty } => { - let mut collected_spans = vec![ByteSpan::from(slice_token.span())]; + let mut collected_spans = if let Some(slice_token) = slice_token { + vec![ByteSpan::from(slice_token.span())] + } else { + vec![] + }; collected_spans.append(&mut ty.leaf_spans()); collected_spans } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/aliases/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/aliases/json_abi_oracle_new_encoding.json old mode 100755 new mode 100644 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/multiple_imports_of_same_reexport/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/multiple_imports_of_same_reexport/json_abi_oracle_new_encoding.json old mode 100755 new mode 100644 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/reexport_paths/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/reexport_paths/json_abi_oracle_new_encoding.json old mode 100755 new mode 100644 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/shadowing_in_reexporting_module/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/shadowing_in_reexporting_module/json_abi_oracle_new_encoding.json old mode 100755 new mode 100644 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_glob_import/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_glob_import/json_abi_oracle_new_encoding.json old mode 100755 new mode 100644 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_item_import/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_item_import/json_abi_oracle_new_encoding.json old mode 100755 new mode 100644 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/visibility/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/visibility/json_abi_oracle_new_encoding.json old mode 100755 new mode 100644 From 68b7b348e452fe9934a2644a77794f8d71414387 Mon Sep 17 00:00:00 2001 From: SwayStar123 <46050679+SwayStar123@users.noreply.github.com> Date: Mon, 5 Aug 2024 14:09:37 +0530 Subject: [PATCH 2/2] Correct code_size function implementation (#6304) ## Description The current code_size function returns a pointer, rather than the value, this pr corrects this mistake. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [x] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: K1-R1 <77465250+K1-R1@users.noreply.github.com> Co-authored-by: IGI-111 --- sway-lib-std/src/call_frames.sw | 7 ++++--- test/src/sdk-harness/test_projects/call_frames/mod.rs | 9 +++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/sway-lib-std/src/call_frames.sw b/sway-lib-std/src/call_frames.sw index 8d69188204d..21b009659c3 100644 --- a/sway-lib-std/src/call_frames.sw +++ b/sway-lib-std/src/call_frames.sw @@ -63,10 +63,11 @@ pub fn msg_asset_id() -> AssetId { /// } /// ``` pub fn code_size() -> u64 { - asm(size, ptr, offset: 576) { + let ptr = asm(size, ptr, offset: 576) { add size fp offset; - size: u64 - } + size: raw_ptr + }; + ptr.read::() } /// Get the first parameter from the current call frame. diff --git a/test/src/sdk-harness/test_projects/call_frames/mod.rs b/test/src/sdk-harness/test_projects/call_frames/mod.rs index bcfaa98f5b1..fe956fb5c43 100644 --- a/test/src/sdk-harness/test_projects/call_frames/mod.rs +++ b/test/src/sdk-harness/test_projects/call_frames/mod.rs @@ -1,4 +1,3 @@ -use fuel_vm::consts::VM_MAX_RAM; use fuels::{accounts::wallet::WalletUnlocked, prelude::*, types::ContractId}; abigen!(Contract( @@ -36,7 +35,9 @@ async fn can_get_id_contract_id_this() { async fn can_get_code_size() { let (instance, _id) = get_call_frames_instance().await; let result = instance.methods().get_code_size().call().await.unwrap(); - assert!(is_within_range(result.value)); + // Check if codesize is between 1000 and 7000. Arbitrary endpoints, current codesize is 6816 + // but the lower bound future proofs against compiler optimizations + assert!(result.value > 1000 && result.value < 7000); } #[tokio::test] @@ -110,7 +111,3 @@ async fn can_get_second_param_multiple_params2() { .unwrap(); assert_eq!(result.value, (300, expected_struct, expected_struct2)); } - -fn is_within_range(n: u64) -> bool { - n > 0 && n <= VM_MAX_RAM -}