diff --git a/compiler/noirc_frontend/src/elaborator/enums.rs b/compiler/noirc_frontend/src/elaborator/enums.rs index 3b57d9af2b9..aabc58fd354 100644 --- a/compiler/noirc_frontend/src/elaborator/enums.rs +++ b/compiler/noirc_frontend/src/elaborator/enums.rs @@ -311,6 +311,14 @@ impl Elaborator<'_> { }); }; + // We want the actual expression's span here, not the innermost one from `type_location()` + let span = expression.location.span; + let syntax_error = |this: &mut Self| { + let errors = ResolverError::InvalidSyntaxInPattern { span }; + this.push_err(errors, this.file); + Pattern::Error + }; + match expression.kind { ExpressionKind::Literal(Literal::Integer(value, negative)) => { let actual = self.interner.next_type_variable_with_kind(Kind::IntegerOrField); @@ -363,10 +371,7 @@ impl Elaborator<'_> { } Err(error) => { self.push_err(error, location.file); - // Default to defining a variable of the same name although this could - // cause further match warnings/errors (e.g. redundant cases). - let id = self.fresh_match_variable(expected_type.clone(), location); - Pattern::Binding(id) + Pattern::Error } } } @@ -402,7 +407,7 @@ impl Elaborator<'_> { if let StatementKind::Expression(expr) = self.interner.get_statement_kind(id) { self.expression_to_pattern(expr.clone(), expected_type, variables_defined) } else { - panic!("Invalid expr kind {expression}") + syntax_error(self) } } @@ -425,9 +430,7 @@ impl Elaborator<'_> { | ExpressionKind::AsTraitPath(_) | ExpressionKind::TypePath(_) | ExpressionKind::Resolved(_) - | ExpressionKind::Error => { - panic!("Invalid expr kind {expression}") - } + | ExpressionKind::Error => syntax_error(self), } } @@ -703,6 +706,7 @@ impl Elaborator<'_> { let (key, cons) = match col.pattern { Pattern::Int(val) => ((val, val), Constructor::Int(val)), Pattern::Range(start, stop) => ((start, stop), Constructor::Range(start, stop)), + Pattern::Error => continue, pattern => { eprintln!("Unexpected pattern for integer type: {pattern:?}"); continue; @@ -931,6 +935,11 @@ enum Pattern { /// 1 <= n < 20. #[allow(unused)] Range(SignedField, SignedField), + + /// An error occurred while translating this pattern. This Pattern kind always translates + /// to a Fail branch in the decision tree, although the compiler is expected to halt + /// with errors before execution. + Error, } #[derive(Clone)] diff --git a/compiler/noirc_frontend/src/hir/resolution/errors.rs b/compiler/noirc_frontend/src/hir/resolution/errors.rs index f5ed1475087..1e6237788c7 100644 --- a/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -182,6 +182,8 @@ pub enum ResolverError { LoopNotYetSupported { span: Span }, #[error("Expected a trait but found {found}")] ExpectedTrait { found: String, span: Span }, + #[error("Invalid syntax in match pattern")] + InvalidSyntaxInPattern { span: Span }, #[error("Variable '{existing}' was already defined in the same match pattern")] VariableAlreadyDefinedInPattern { existing: Ident, new_span: Span }, } @@ -694,6 +696,12 @@ impl<'a> From<&'a ResolverError> for Diagnostic { String::new(), *span) } + ResolverError::InvalidSyntaxInPattern { span } => { + Diagnostic::simple_error( + "Invalid syntax in match pattern".into(), + "Only literal, constructor, and variable patterns are allowed".into(), + *span) + }, ResolverError::VariableAlreadyDefinedInPattern { existing, new_span } => { let message = format!("Variable `{existing}` was already defined in the same match pattern"); let secondary = format!("`{existing}` redefined here");