Add some security checks, typecheck for condition to be a boolean

This commit is contained in:
Sofia 2025-07-07 23:25:07 +03:00
parent a366d22470
commit 9b68ecb614
4 changed files with 50 additions and 16 deletions

View File

@ -1,6 +1,6 @@
// Main
fn main() -> i32 {
return fibonacci(3);
return (fibonacci(3) < 5) + 5;
}
// Fibonacci

View File

@ -183,6 +183,7 @@ impl mir::Expression {
pub fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
match &self.0 {
mir::ExprKind::Variable(varref) => {
varref.0.is_known().expect("variable type unknown");
let v = scope
.stack_values
.get(&varref.1)
@ -191,6 +192,17 @@ impl mir::Expression {
}
mir::ExprKind::Literal(lit) => Some(lit.as_const(&mut scope.block)),
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
lhs_exp
.return_type()
.expect("No ret type in lhs?")
.is_known()
.expect("lhs ret type is unknown");
rhs_exp
.return_type()
.expect("No ret type in rhs?")
.is_known()
.expect("rhs ret type is unknown");
let lhs = lhs_exp.codegen(scope).expect("lhs has no return value");
let rhs = rhs_exp.codegen(scope).expect("rhs has no return value");
Some(match binop {
@ -202,16 +214,17 @@ impl mir::Expression {
}
mir::BinaryOperator::Mult => todo!(),
mir::BinaryOperator::And => todo!(),
mir::BinaryOperator::Logic(l) => {
let ret_type = lhs_exp.return_type().expect("No ret type in lhs?");
scope
.block
.build(InstructionKind::ICmp(l.int_predicate(), lhs, rhs))
.unwrap()
}
mir::BinaryOperator::Logic(l) => scope
.block
.build(InstructionKind::ICmp(l.int_predicate(), lhs, rhs))
.unwrap(),
})
}
mir::ExprKind::FunctionCall(call) => {
call.return_type
.is_known()
.expect("function return type unknown");
let params = call
.parameters
.iter()
@ -293,6 +306,7 @@ impl TypeKind {
match &self {
TypeKind::I32 => Type::I32,
TypeKind::I16 => Type::I16,
TypeKind::Bool => Type::Bool,
TypeKind::Void => panic!("Void not a supported type"),
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
}

View File

@ -39,6 +39,8 @@ pub enum TypeKind {
I32,
#[error("i16")]
I16,
#[error("bool")]
Bool,
#[error("void")]
Void,
#[error(transparent)]
@ -51,12 +53,35 @@ pub enum VagueType {
Unknown,
}
impl TypeKind {
pub fn is_known(&self) -> Result<TypeKind, VagueType> {
if let TypeKind::Vague(vague) = self {
Err(*vague)
} else {
Ok(*self)
}
}
}
impl TypeKind {
pub fn signed(&self) -> bool {
match self {
TypeKind::Void => false,
TypeKind::Vague(_) => false,
_ => true,
}
}
pub fn is_maths(&self) -> bool {
use TypeKind::*;
match &self {
I32 => true,
I16 => true,
Bool => true,
Vague(_) => false,
Void => false,
}
}
}
#[derive(Debug, Clone, Copy)]

View File

@ -171,12 +171,10 @@ impl FunctionDefinition {
}
let return_type = self.return_type.clone();
dbg!(&return_type);
let inferred = match &self.kind {
FunctionDefinitionKind::Local(block, _) => block.typecheck(state, scope),
FunctionDefinitionKind::Extern => Ok(Vague(Unknown)),
};
dbg!(&inferred);
match inferred {
Ok(t) => try_collapse(&return_type, &t)
@ -295,7 +293,8 @@ impl Expression {
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
// TODO make sure cond_res is Boolean here
let cond_res = cond.typecheck(state, scope);
state.ok(cond_res, cond.1);
let cond_t = state.or_else(cond_res, Vague(Unknown), cond.1);
state.ok(cond_t.collapse_into(&Bool), cond.1);
let lhs_res = lhs.typecheck(state, scope);
let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.meta);
@ -314,11 +313,7 @@ impl Expression {
impl TypeKind {
fn assert_known(&self) -> Result<TypeKind, ErrorKind> {
if let Vague(vague) = self {
Err(ErrorKind::TypeIsVague(*vague))
} else {
Ok(*self)
}
self.is_known().map_err(ErrorKind::TypeIsVague)
}
}