diff --git a/crates/noirc_frontend/src/hir/type_check/expr.rs b/crates/noirc_frontend/src/hir/type_check/expr.rs index 13b2211f087..1b3faecf399 100644 --- a/crates/noirc_frontend/src/hir/type_check/expr.rs +++ b/crates/noirc_frontend/src/hir/type_check/expr.rs @@ -775,8 +775,10 @@ impl<'interner> TypeChecker<'interner> { let ret = self.interner.next_type_variable(); let args = vecmap(args, |(arg, _)| arg); let expected = Type::Function(args, Box::new(ret.clone())); - *binding.borrow_mut() = TypeBinding::Bound(expected); + if let Err(error) = binding.borrow_mut().bind_to(expected, span) { + self.errors.push(error); + } ret } Type::Function(parameters, ret) => { diff --git a/crates/noirc_frontend/src/hir_def/types.rs b/crates/noirc_frontend/src/hir_def/types.rs index 9441307bf28..68660aa4d9d 100644 --- a/crates/noirc_frontend/src/hir_def/types.rs +++ b/crates/noirc_frontend/src/hir_def/types.rs @@ -294,6 +294,20 @@ impl TypeBinding { pub fn is_unbound(&self) -> bool { matches!(self, TypeBinding::Unbound(_)) } + + pub fn bind_to(&mut self, binding: Type, span: Span) -> Result<(), TypeCheckError> { + match self { + TypeBinding::Bound(_) => panic!("Tried to bind an already bound type variable!"), + TypeBinding::Unbound(id) => { + if binding.occurs(*id) { + Err(TypeCheckError::TypeAnnotationsNeeded { span }) + } else { + *self = TypeBinding::Bound(binding); + Ok(()) + } + } + } + } } /// A unique ID used to differentiate different type variables