From 34ad6669b210173ddf0484b04e47161b2cfbcadf Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 12 Nov 2024 16:49:46 -0300 Subject: [PATCH] fix: parse Slice type in SSa (#6507) --- .../src/ssa/opt/as_slice_length.rs | 31 ++++++++++++++++++ compiler/noirc_evaluator/src/ssa/parser.rs | 32 +++++++++++-------- .../noirc_evaluator/src/ssa/parser/lexer.rs | 2 +- .../noirc_evaluator/src/ssa/parser/tests.rs | 12 +++++++ 4 files changed, 62 insertions(+), 15 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/as_slice_length.rs b/compiler/noirc_evaluator/src/ssa/opt/as_slice_length.rs index 59917e8589b..76705dcc9db 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/as_slice_length.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/as_slice_length.rs @@ -75,3 +75,34 @@ fn replace_known_slice_lengths( func.dfg.set_value_from_id(original_slice_length, known_length); }); } + +#[cfg(test)] +mod test { + use crate::ssa::opt::assert_normalized_ssa_equals; + + use super::Ssa; + + #[test] + fn as_slice_length_optimization() { + // In this code we expect `return v2` to be replaced with `return u32 3` because + // that's the length of the v0 array. + let src = " + acir(inline) fn main f0 { + b0(v0: [Field; 3]): + v2, v3 = call as_slice(v0) -> (u32, [Field]) + return v2 + } + "; + let ssa = Ssa::from_str(src).unwrap(); + + let expected = " + acir(inline) fn main f0 { + b0(v0: [Field; 3]): + v2, v3 = call as_slice(v0) -> (u32, [Field]) + return u32 3 + } + "; + let ssa = ssa.as_slice_optimization(); + assert_normalized_ssa_equals(ssa, expected); + } +} diff --git a/compiler/noirc_evaluator/src/ssa/parser.rs b/compiler/noirc_evaluator/src/ssa/parser.rs index bfdb08f85e6..717d2691b2f 100644 --- a/compiler/noirc_evaluator/src/ssa/parser.rs +++ b/compiler/noirc_evaluator/src/ssa/parser.rs @@ -81,15 +81,15 @@ impl Debug for SsaErrorWithSource { pub(crate) enum SsaError { #[error("{0}")] ParserError(ParserError), - #[error("Unknown variable `{0}`")] + #[error("Unknown variable '{0}'")] UnknownVariable(Identifier), - #[error("Unknown block `{0}`")] + #[error("Unknown block '{0}'")] UnknownBlock(Identifier), - #[error("Unknown function `{0}`")] + #[error("Unknown function '{0}'")] UnknownFunction(Identifier), #[error("Mismatched return values")] MismatchedReturnValues { returns: Vec, expected: usize }, - #[error("Variable `{0}` already defined")] + #[error("Variable '{0}' already defined")] VariableAlreadyDefined(Identifier), } @@ -647,10 +647,14 @@ impl<'a> Parser<'a> { if self.eat(Token::LeftBracket)? { let element_types = self.parse_types()?; - self.eat_or_error(Token::Semicolon)?; - let length = self.eat_int_or_error()?; - self.eat_or_error(Token::RightBracket)?; - return Ok(Type::Array(Arc::new(element_types), length.to_u128() as usize)); + if self.eat(Token::Semicolon)? { + let length = self.eat_int_or_error()?; + self.eat_or_error(Token::RightBracket)?; + return Ok(Type::Array(Arc::new(element_types), length.to_u128() as usize)); + } else { + self.eat_or_error(Token::RightBracket)?; + return Ok(Type::Slice(Arc::new(element_types))); + } } if let Some(typ) = self.parse_mutable_reference_type()? { @@ -857,19 +861,19 @@ impl<'a> Parser<'a> { pub(crate) enum ParserError { #[error("{0}")] LexerError(LexerError), - #[error("Expected {token}, found {token}")] + #[error("Expected '{token}', found '{found}'")] ExpectedToken { token: Token, found: Token, span: Span }, #[error("Expected one of {tokens:?}, found {found}")] ExpectedOneOfTokens { tokens: Vec, found: Token, span: Span }, - #[error("Expected an identifier, found {found}")] + #[error("Expected an identifier, found '{found}'")] ExpectedIdentifier { found: Token, span: Span }, - #[error("Expected an int, found {found}")] + #[error("Expected an int, found '{found}'")] ExpectedInt { found: Token, span: Span }, - #[error("Expected a type, found {found}")] + #[error("Expected a type, found '{found}'")] ExpectedType { found: Token, span: Span }, - #[error("Expected an instruction or terminator, found {found}")] + #[error("Expected an instruction or terminator, found '{found}'")] ExpectedInstructionOrTerminator { found: Token, span: Span }, - #[error("Expected a value, found {found}")] + #[error("Expected a value, found '{found}'")] ExpectedValue { found: Token, span: Span }, #[error("Multiple return values only allowed for call")] MultipleReturnValuesOnlyAllowedForCall { second_target: Identifier }, diff --git a/compiler/noirc_evaluator/src/ssa/parser/lexer.rs b/compiler/noirc_evaluator/src/ssa/parser/lexer.rs index 456e5ec15e0..ac4c3b77205 100644 --- a/compiler/noirc_evaluator/src/ssa/parser/lexer.rs +++ b/compiler/noirc_evaluator/src/ssa/parser/lexer.rs @@ -240,7 +240,7 @@ type SpannedTokenResult = Result; #[derive(Debug, Error)] pub(crate) enum LexerError { - #[error("Unexpected character: {char}")] + #[error("Unexpected character: {char:?}")] UnexpectedCharacter { char: char, span: Span }, #[error("Invalid integer literal")] InvalidIntegerLiteral { span: Span, found: String }, diff --git a/compiler/noirc_evaluator/src/ssa/parser/tests.rs b/compiler/noirc_evaluator/src/ssa/parser/tests.rs index 1ec0161649b..3ed6be57b5e 100644 --- a/compiler/noirc_evaluator/src/ssa/parser/tests.rs +++ b/compiler/noirc_evaluator/src/ssa/parser/tests.rs @@ -413,3 +413,15 @@ fn test_parses_with_comments() { let ssa = Ssa::from_str(src).unwrap(); assert_normalized_ssa_equals(ssa, expected); } + +#[test] +fn test_slice() { + let src = " + acir(inline) fn main f0 { + b0(v0: [Field; 3]): + v2, v3 = call as_slice(v0) -> (u32, [Field]) + return + } + "; + assert_ssa_roundtrip(src); +}