Skip to content

Commit 1544786

Browse files
authored
fix: Perform occurs check before binding function types (#2027)
Fix binding function types without doing an occurs check
1 parent 8adc57c commit 1544786

File tree

2 files changed

+17
-1
lines changed

2 files changed

+17
-1
lines changed

crates/noirc_frontend/src/hir/type_check/expr.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -775,8 +775,10 @@ impl<'interner> TypeChecker<'interner> {
775775
let ret = self.interner.next_type_variable();
776776
let args = vecmap(args, |(arg, _)| arg);
777777
let expected = Type::Function(args, Box::new(ret.clone()));
778-
*binding.borrow_mut() = TypeBinding::Bound(expected);
779778

779+
if let Err(error) = binding.borrow_mut().bind_to(expected, span) {
780+
self.errors.push(error);
781+
}
780782
ret
781783
}
782784
Type::Function(parameters, ret) => {

crates/noirc_frontend/src/hir_def/types.rs

+14
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,20 @@ impl TypeBinding {
294294
pub fn is_unbound(&self) -> bool {
295295
matches!(self, TypeBinding::Unbound(_))
296296
}
297+
298+
pub fn bind_to(&mut self, binding: Type, span: Span) -> Result<(), TypeCheckError> {
299+
match self {
300+
TypeBinding::Bound(_) => panic!("Tried to bind an already bound type variable!"),
301+
TypeBinding::Unbound(id) => {
302+
if binding.occurs(*id) {
303+
Err(TypeCheckError::TypeAnnotationsNeeded { span })
304+
} else {
305+
*self = TypeBinding::Bound(binding);
306+
Ok(())
307+
}
308+
}
309+
}
310+
}
297311
}
298312

299313
/// A unique ID used to differentiate different type variables

0 commit comments

Comments
 (0)