diff --git a/crates/noirc_frontend/src/hir/type_check/expr.rs b/crates/noirc_frontend/src/hir/type_check/expr.rs index 41d9843802..ac49dd01fe 100644 --- a/crates/noirc_frontend/src/hir/type_check/expr.rs +++ b/crates/noirc_frontend/src/hir/type_check/expr.rs @@ -837,11 +837,13 @@ impl<'interner> TypeChecker<'interner> { } for (param, (arg, _, arg_span)) in fn_params.iter().zip(callsite_args) { - self.unify(arg, param, || TypeCheckError::TypeMismatch { - expected_typ: param.to_string(), - expr_typ: arg.to_string(), - expr_span: *arg_span, - }); + if arg.try_unify_allow_incompat_lambdas(param).is_err() { + self.errors.push(TypeCheckError::TypeMismatch { + expected_typ: param.to_string(), + expr_typ: arg.to_string(), + expr_span: *arg_span, + }); + } } fn_ret.clone() diff --git a/crates/noirc_frontend/src/hir/type_check/mod.rs b/crates/noirc_frontend/src/hir/type_check/mod.rs index a047b417b3..4a09139c99 100644 --- a/crates/noirc_frontend/src/hir/type_check/mod.rs +++ b/crates/noirc_frontend/src/hir/type_check/mod.rs @@ -63,28 +63,33 @@ pub fn type_check_func(interner: &mut NodeInterner, func_id: FuncId) -> Vec Result<(), UnificationError> { + use Type::*; + use TypeVariableKind::*; + + match (self, other) { + (TypeVariable(binding, Normal), other) | (other, TypeVariable(binding, Normal)) => { + if let TypeBinding::Bound(link) = &*binding.borrow() { + return link.try_unify_allow_incompat_lambdas(other); + } + + other.try_bind_to(binding) + } + (Function(params_a, ret_a, _), Function(params_b, ret_b, _)) => { + if params_a.len() == params_b.len() { + for (a, b) in params_a.iter().zip(params_b.iter()) { + a.try_unify_allow_incompat_lambdas(b)?; + } + + // no check for environments here! + ret_b.try_unify_allow_incompat_lambdas(ret_a) + } else { + Err(UnificationError) + } + } + _ => self.try_unify(other), + } + } + + /// Similar to `unify` but if the check fails this will attempt to coerce the /// argument to the target type. When this happens, the given expression is wrapped in /// a new expression to convert its type. E.g. `array` -> `array.as_slice()` /// @@ -923,7 +951,7 @@ impl Type { // If we have an array and our target is a slice if matches!(size1, Type::Constant(_)) && matches!(size2, Type::NotConstant) { // Still have to ensure the element types match. - // Don't need to issue an error here if not, it will be done in make_subtype_of_with_coercions + // Don't need to issue an error here if not, it will be done in unify_with_coercions if element1.try_unify(element2).is_ok() { convert_array_expression_to_slice(expression, this, target, interner); return true;