diff --git a/src/ast/compiler/type_checker.rs b/src/ast/compiler/type_checker.rs index 21342c6..2fefbd4 100644 --- a/src/ast/compiler/type_checker.rs +++ b/src/ast/compiler/type_checker.rs @@ -1513,16 +1513,8 @@ impl TypeChecker { self.check_node(args, ctx, diag) }; - if let Some(expected_ty) = &ctx.current_params_ty - && !expected_ty.is_assignable_from(&args_typed.ty) - { - diag.push_error( - format!( - "Type mismatch in 'again' call: expected {}, but got {}", - expected_ty.display_compact(), args_typed.ty.display_compact() - ), - Some(node.identity.clone()), - ); + if let Some(expected_ty) = &ctx.current_params_ty { + self.unify(expected_ty.clone(), args_typed.ty.clone(), diag); } ( diff --git a/tests/error_recovery.rs b/tests/error_recovery.rs index 1eb4aa9..fea1a84 100644 --- a/tests/error_recovery.rs +++ b/tests/error_recovery.rs @@ -160,3 +160,17 @@ fn test_error_recovery_multiple_errors() { .any(|m| m.contains("no matching overload")) ); } + +#[test] +fn test_again_type_mismatch() { + let env = Environment::new(); + // (again "text") should fail: parameter n is int (from call site), not string. + // Without this check, the program would loop forever. + let result = env.run_script( + r#"(do (def f (fn [n] (if (= n 0) n (again "text")))) (f 3))"#, + ); + assert!( + result.is_err(), + "again with wrong type should be a compile error, not an infinite loop" + ); +}