From 08e481d6e26cd3e660da3041ed7c5fd81c9b76a8 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 7 Jan 2025 08:02:35 -0300 Subject: [PATCH] fix: error on missing function parameters --- compiler/noirc_frontend/src/parser/errors.rs | 9 ++++++ .../src/parser/parser/function.rs | 31 ++++++++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index 32cacf5e4ed..1b16b911b18 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -112,6 +112,8 @@ pub enum ParserErrorReason { DeprecatedAttributeExpectsAStringArgument, #[error("Unsafe block must start with a safety comment")] MissingSafetyComment, + #[error("Missing parameters for function definition")] + MissingParametersForFunctionDefinition, } /// Represents a parsing error, or a parsing error in the making. @@ -285,6 +287,13 @@ impl<'a> From<&'a ParserError> for Diagnostic { "Unsafe block must start with a safety comment: //@safety".into(), error.span, ), + ParserErrorReason::MissingParametersForFunctionDefinition => { + Diagnostic::simple_error( + "Missing parameters for function definition".into(), + "Add a parameter list: `()`".into(), + error.span, + ) + } other => Diagnostic::simple_error(format!("{other}"), String::new(), error.span), }, None => { diff --git a/compiler/noirc_frontend/src/parser/parser/function.rs b/compiler/noirc_frontend/src/parser/parser/function.rs index 438757b5d79..29e864200f3 100644 --- a/compiler/noirc_frontend/src/parser/parser/function.rs +++ b/compiler/noirc_frontend/src/parser/parser/function.rs @@ -94,6 +94,17 @@ impl<'a> Parser<'a> { let generics = self.parse_generics(); let parameters = self.parse_function_parameters(allow_self); + let parameters = match parameters { + Some(parameters) => parameters, + None => { + self.push_error( + ParserErrorReason::MissingParametersForFunctionDefinition, + name.span(), + ); + Vec::new() + } + }; + let (return_type, return_visibility) = if self.eat(Token::Arrow) { let visibility = self.parse_visibility(); (FunctionReturnType::Ty(self.parse_type_or_error()), visibility) @@ -131,14 +142,14 @@ impl<'a> Parser<'a> { /// FunctionParametersList = FunctionParameter ( ',' FunctionParameter )* ','? /// /// FunctionParameter = Visibility PatternOrSelf ':' Type - fn parse_function_parameters(&mut self, allow_self: bool) -> Vec { + fn parse_function_parameters(&mut self, allow_self: bool) -> Option> { if !self.eat_left_paren() { - return Vec::new(); + return None; } - self.parse_many("parameters", separated_by_comma_until_right_paren(), |parser| { + Some(self.parse_many("parameters", separated_by_comma_until_right_paren(), |parser| { parser.parse_function_parameter(allow_self) - }) + })) } fn parse_function_parameter(&mut self, allow_self: bool) -> Option { @@ -490,4 +501,16 @@ mod tests { assert!(noir_function.def.is_unconstrained); assert_eq!(noir_function.def.visibility, ItemVisibility::Public); } + + #[test] + fn parse_function_without_parentheses() { + let src = " + fn foo {} + ^^^ + "; + let (src, span) = get_source_with_error_span(src); + let (_, errors) = parse_program(&src); + let reason = get_single_error_reason(&errors, span); + assert!(matches!(reason, ParserErrorReason::MissingParametersForFunctionDefinition)); + } }