use codegen_lang::{CodegenError, compile};
use ir_lang::{BinOp, Builder, Type, ValidationError};
fn reason(func: ir_lang::Function) -> ValidationError {
match compile(&func) {
Err(CodegenError::InvalidIr(reason)) => reason,
Err(other) => panic!("expected an InvalidIr error, got {other:?}"),
Ok(_) => panic!("a malformed function must not compile"),
}
}
#[test]
fn test_unterminated_block_is_rejected() {
let func = Builder::new("f", &[], Type::Unit).finish();
assert!(matches!(
reason(func),
ValidationError::MissingTerminator { .. }
));
}
#[test]
fn test_missing_return_value_is_rejected() {
let mut b = Builder::new("f", &[], Type::Int);
b.ret(None);
assert!(matches!(
reason(b.finish()),
ValidationError::ReturnValueExpected { .. }
));
}
#[test]
fn test_type_mismatched_operands_are_rejected() {
let mut b = Builder::new("f", &[Type::Int, Type::Bool], Type::Int);
let x = b.block_params(b.entry())[0];
let flag = b.block_params(b.entry())[1];
let bad = b.bin(BinOp::Add, x, flag);
b.ret(Some(bad));
assert!(matches!(
reason(b.finish()),
ValidationError::TypeMismatch { .. }
));
}
#[test]
fn test_branch_to_entry_is_rejected() {
let mut b = Builder::new("f", &[], Type::Unit);
let entry = b.entry();
b.jump(entry, &[]);
assert!(matches!(
reason(b.finish()),
ValidationError::EntryBranchTarget { .. }
));
}
#[test]
fn test_argument_count_mismatch_is_rejected() {
let mut b = Builder::new("f", &[], Type::Int);
let exit = b.create_block(&[Type::Int]);
b.jump(exit, &[]);
b.switch_to(exit);
let p = b.block_params(exit)[0];
b.ret(Some(p));
assert!(matches!(
reason(b.finish()),
ValidationError::ArgCountMismatch { .. }
));
}