diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index 181f787ce08..0e9666bd686 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -134,6 +134,14 @@ impl Elaborator<'_> { } }; + if fields.len() != field_types.len() { + self.push_err(TypeCheckError::TupleMismatch { + tuple_types: field_types.clone(), + actual_count: fields.len(), + location, + }); + } + let fields = vecmap(fields.into_iter().enumerate(), |(i, field)| { let field_type = field_types.get(i).cloned().unwrap_or(Type::Error); self.elaborate_pattern_mut( diff --git a/compiler/noirc_frontend/src/hir/type_check/errors.rs b/compiler/noirc_frontend/src/hir/type_check/errors.rs index 8c2c7150902..3996378460f 100644 --- a/compiler/noirc_frontend/src/hir/type_check/errors.rs +++ b/compiler/noirc_frontend/src/hir/type_check/errors.rs @@ -2,6 +2,7 @@ use std::collections::BTreeSet; use std::rc::Rc; use acvm::FieldElement; +use iter_extended::vecmap; use noirc_errors::CustomDiagnostic as Diagnostic; use noirc_errors::Location; use thiserror::Error; @@ -249,6 +250,8 @@ pub enum TypeCheckError { /// This error is used for types like integers which have too many variants to enumerate #[error("Missing cases: `{typ}` is non-empty")] MissingManyCases { typ: String, location: Location }, + #[error("Expected a tuple with {} elements, found one with {} elements", tuple_types.len(), actual_count)] + TupleMismatch { tuple_types: Vec, actual_count: usize, location: Location }, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -340,7 +343,8 @@ impl TypeCheckError { | TypeCheckError::UnreachableCase { location } | TypeCheckError::MissingCases { location, .. } | TypeCheckError::MissingManyCases { location, .. } - | TypeCheckError::NestedUnsafeBlock { location } => *location, + | TypeCheckError::NestedUnsafeBlock { location } + | TypeCheckError::TupleMismatch { location, .. } => *location, TypeCheckError::DuplicateNamedTypeArg { name: ident, .. } | TypeCheckError::NoSuchNamedTypeArg { name: ident, .. } => ident.location(), @@ -726,6 +730,15 @@ impl<'a> From<&'a TypeCheckError> for Diagnostic { let secondary = "Try adding a match-all pattern: `_`".to_string(); Diagnostic::simple_error(msg, secondary, *location) }, + TypeCheckError::TupleMismatch { tuple_types, actual_count, location } => { + let msg = format!( + "Expected a tuple with {} elements, found one with {} elements", + tuple_types.len(), + actual_count + ); + let secondary = format!("The expression the tuple is assigned to has type `({})`", vecmap(tuple_types, ToString::to_string).join(",")); + Diagnostic::simple_error(msg, secondary, *location) + } } } } diff --git a/test_programs/compile_failure/tuple_mismatch/Nargo.toml b/test_programs/compile_failure/tuple_mismatch/Nargo.toml new file mode 100644 index 00000000000..9e4b8b34d20 --- /dev/null +++ b/test_programs/compile_failure/tuple_mismatch/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "tuple_mismatch" +type = "bin" +authors = [""] +compiler_version = ">=0.33.0" + +[dependencies] diff --git a/test_programs/compile_failure/tuple_mismatch/src/main.nr b/test_programs/compile_failure/tuple_mismatch/src/main.nr new file mode 100644 index 00000000000..5d1b2b9a65b --- /dev/null +++ b/test_programs/compile_failure/tuple_mismatch/src/main.nr @@ -0,0 +1,3 @@ +fn main() { + let (_x, _y) = (1, 2, 3); +} diff --git a/test_programs/compile_failure/tuple_mismatch/stderr.txt b/test_programs/compile_failure/tuple_mismatch/stderr.txt new file mode 100644 index 00000000000..767d197e1c4 --- /dev/null +++ b/test_programs/compile_failure/tuple_mismatch/stderr.txt @@ -0,0 +1,8 @@ +error: Expected a tuple with 3 elements, found one with 2 elements + ┌─ src/main.nr:2:9 + │ +2 │ let (_x, _y) = (1, 2, 3); + │ -------- The expression the tuple is assigned to has type `(Field,Field,Field)` + │ + +Aborting due to 1 previous error