Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 262 additions & 0 deletions crates/kodo_codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1811,6 +1811,268 @@ mod tests {
assert_eq!(HeapKind::Set, HeapKind::Set);
}

// ---------------------------------------------------------------
// instruction.rs translation path tests
// ---------------------------------------------------------------

#[test]
fn compile_add_two_ints() {
let func = MirFunction {
name: "add_ints".to_string(),
return_type: Type::Int,
param_count: 0,
locals: vec![],
blocks: vec![BasicBlock {
id: BlockId(0),
instructions: vec![],
terminator: Terminator::Return(Value::BinOp(
kodo_ast::BinOp::Add,
Box::new(Value::IntConst(10)),
Box::new(Value::IntConst(20)),
)),
}],
entry: BlockId(0),
};
let result = compile_module(&[func], &CodegenOptions::default(), None);
assert!(result.is_ok(), "add two ints failed: {result:?}");
}

#[test]
fn compile_subtract_ints() {
let func = MirFunction {
name: "sub_ints".to_string(),
return_type: Type::Int,
param_count: 0,
locals: vec![],
blocks: vec![BasicBlock {
id: BlockId(0),
instructions: vec![],
terminator: Terminator::Return(Value::BinOp(
kodo_ast::BinOp::Sub,
Box::new(Value::IntConst(100)),
Box::new(Value::IntConst(37)),
)),
}],
entry: BlockId(0),
};
let result = compile_module(&[func], &CodegenOptions::default(), None);
assert!(result.is_ok(), "subtract ints failed: {result:?}");
}

#[test]
fn compile_multiply_ints() {
let func = MirFunction {
name: "mul_ints".to_string(),
return_type: Type::Int,
param_count: 0,
locals: vec![],
blocks: vec![BasicBlock {
id: BlockId(0),
instructions: vec![],
terminator: Terminator::Return(Value::BinOp(
kodo_ast::BinOp::Mul,
Box::new(Value::IntConst(6)),
Box::new(Value::IntConst(7)),
)),
}],
entry: BlockId(0),
};
let result = compile_module(&[func], &CodegenOptions::default(), None);
assert!(result.is_ok(), "multiply ints failed: {result:?}");
}

#[test]
fn compile_divide_ints() {
let func = MirFunction {
name: "div_ints".to_string(),
return_type: Type::Int,
param_count: 0,
locals: vec![],
blocks: vec![BasicBlock {
id: BlockId(0),
instructions: vec![],
terminator: Terminator::Return(Value::BinOp(
kodo_ast::BinOp::Div,
Box::new(Value::IntConst(84)),
Box::new(Value::IntConst(2)),
)),
}],
entry: BlockId(0),
};
let result = compile_module(&[func], &CodegenOptions::default(), None);
assert!(result.is_ok(), "divide ints failed: {result:?}");
}

#[test]
fn compile_compare_ints_eq() {
let func = MirFunction {
name: "compare_eq".to_string(),
return_type: Type::Bool,
param_count: 0,
locals: vec![],
blocks: vec![BasicBlock {
id: BlockId(0),
instructions: vec![],
terminator: Terminator::Return(Value::BinOp(
kodo_ast::BinOp::Eq,
Box::new(Value::IntConst(42)),
Box::new(Value::IntConst(42)),
)),
}],
entry: BlockId(0),
};
let result = compile_module(&[func], &CodegenOptions::default(), None);
assert!(
result.is_ok(),
"compare ints (Eq) with Bool return failed: {result:?}"
);
}

#[test]
fn compile_string_const_local() {
let func = MirFunction {
name: "str_local".to_string(),
return_type: Type::Unit,
param_count: 0,
locals: vec![Local {
id: LocalId(0),
ty: Type::String,
mutable: false,
}],
blocks: vec![BasicBlock {
id: BlockId(0),
instructions: vec![Instruction::Assign(
LocalId(0),
Value::StringConst("hello".to_string()),
)],
terminator: Terminator::Return(Value::Unit),
}],
entry: BlockId(0),
};
let result = compile_module(&[func], &CodegenOptions::default(), None);
assert!(
result.is_ok(),
"string const local assignment failed: {result:?}"
);
}

#[test]
fn compile_function_call_in_body() {
let printer = MirFunction {
name: "print_int".to_string(),
return_type: Type::Unit,
param_count: 1,
locals: vec![
Local {
id: LocalId(0),
ty: Type::Int,
mutable: false,
},
Local {
id: LocalId(1),
ty: Type::Unit,
mutable: false,
},
],
blocks: vec![BasicBlock {
id: BlockId(0),
instructions: vec![],
terminator: Terminator::Return(Value::Unit),
}],
entry: BlockId(0),
};
let caller = MirFunction {
name: "call_print_int".to_string(),
return_type: Type::Unit,
param_count: 0,
locals: vec![Local {
id: LocalId(0),
ty: Type::Unit,
mutable: false,
}],
blocks: vec![BasicBlock {
id: BlockId(0),
instructions: vec![Instruction::Call {
dest: LocalId(0),
callee: "print_int".to_string(),
args: vec![Value::IntConst(99)],
}],
terminator: Terminator::Return(Value::Unit),
}],
entry: BlockId(0),
};
let result = compile_module(&[printer, caller], &CodegenOptions::default(), None);
assert!(result.is_ok(), "function call in body failed: {result:?}");
}

#[test]
fn compile_multiple_blocks_with_jump() {
let func = MirFunction {
name: "two_blocks".to_string(),
return_type: Type::Int,
param_count: 0,
locals: vec![],
blocks: vec![
BasicBlock {
id: BlockId(0),
instructions: vec![],
terminator: Terminator::Goto(BlockId(1)),
},
BasicBlock {
id: BlockId(1),
instructions: vec![],
terminator: Terminator::Return(Value::IntConst(7)),
},
],
entry: BlockId(0),
};
let result = compile_module(&[func], &CodegenOptions::default(), None);
assert!(
result.is_ok(),
"multiple blocks with jump failed: {result:?}"
);
}

#[test]
fn compile_bool_const_return() {
let func = MirFunction {
name: "always_true".to_string(),
return_type: Type::Bool,
param_count: 0,
locals: vec![],
blocks: vec![BasicBlock {
id: BlockId(0),
instructions: vec![],
terminator: Terminator::Return(Value::BoolConst(true)),
}],
entry: BlockId(0),
};
let result = compile_module(&[func], &CodegenOptions::default(), None);
assert!(result.is_ok(), "bool const return failed: {result:?}");
}

#[test]
fn compile_local_assign_and_return() {
let func = MirFunction {
name: "pass_through".to_string(),
return_type: Type::Int,
param_count: 0,
locals: vec![Local {
id: LocalId(0),
ty: Type::Int,
mutable: false,
}],
blocks: vec![BasicBlock {
id: BlockId(0),
instructions: vec![Instruction::Assign(LocalId(0), Value::IntConst(55))],
terminator: Terminator::Return(Value::Local(LocalId(0))),
}],
entry: BlockId(0),
};
let result = compile_module(&[func], &CodegenOptions::default(), None);
assert!(result.is_ok(), "local assign and return failed: {result:?}");
}

// ---------------------------------------------------------------
// CodegenOptions tests
// ---------------------------------------------------------------
Expand Down
26 changes: 26 additions & 0 deletions crates/kodo_types/src/checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ pub struct TypeChecker {
/// When calling an async function, the return type is automatically wrapped
/// in `Future<T>` so that `await` can unwrap it.
pub(crate) async_fn_names: std::collections::HashSet<String>,
/// Trust configuration for identity verification in `@reviewed_by` annotations.
///
/// When populated from `kodo.toml`'s `[trust]` section, reviewer names are
/// cross-checked against known agents (E0263) and optional allowlists (E0264).
/// Defaults to empty lists, which disables identity checks entirely.
pub(crate) trust_config: crate::confidence::TrustConfig,
}

impl TypeChecker {
Expand Down Expand Up @@ -190,11 +196,21 @@ impl TypeChecker {
map_for_in_spans: Vec::new(),
set_for_in_spans: Vec::new(),
async_fn_names: std::collections::HashSet::new(),
trust_config: crate::confidence::TrustConfig::default(),
};
checker.register_builtins();
checker
}

/// Sets the trust configuration for annotation identity verification.
///
/// Call this before `check_module` to enable forgery detection. The checker
/// will reject `@reviewed_by(human: "X")` if X appears in `known_agents`
/// (E0263) or is absent from `human_reviewers` when that list is non-empty (E0264).
pub fn set_trust_config(&mut self, config: crate::confidence::TrustConfig) {
self.trust_config = config;
}

/// Registers a module name as imported, enabling qualified calls like `mod.func()`.
pub fn register_imported_module(&mut self, name: String) {
self.imported_module_names.insert(name);
Expand Down Expand Up @@ -799,6 +815,10 @@ impl TypeChecker {
Self::check_annotation_policies(func)?;
}

for func in &module.functions {
self.validate_reviewer_identity(func)?;
}

let min_confidence = module
.meta
.as_ref()
Expand Down Expand Up @@ -1368,6 +1388,12 @@ impl TypeChecker {
}
}

for func in &module.functions {
if let Err(e) = self.validate_reviewer_identity(func) {
errors.push(e);
}
}

let min_confidence = module
.meta
.as_ref()
Expand Down
Loading
Loading