diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs
index 32cacf5e4e..1b16b911b1 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 438757b5d7..29e864200f 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));
+ }
}