Refactor 'again' type check to use unify
This change replaces a manual type check for the `again` function with a call to the generic `unify` function. This improves consistency and leverages existing type-checking logic. A new test case `test_again_type_mismatch` has been added to specifically verify that type mismatches in `again` calls are caught at compile time, preventing potential infinite loops.
This commit is contained in:
@@ -1513,16 +1513,8 @@ impl TypeChecker {
|
|||||||
self.check_node(args, ctx, diag)
|
self.check_node(args, ctx, diag)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(expected_ty) = &ctx.current_params_ty
|
if let Some(expected_ty) = &ctx.current_params_ty {
|
||||||
&& !expected_ty.is_assignable_from(&args_typed.ty)
|
self.unify(expected_ty.clone(), args_typed.ty.clone(), diag);
|
||||||
{
|
|
||||||
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()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -160,3 +160,17 @@ fn test_error_recovery_multiple_errors() {
|
|||||||
.any(|m| m.contains("no matching overload"))
|
.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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user