Add some security checks, typecheck for condition to be a boolean
This commit is contained in:
		
							parent
							
								
									a366d22470
								
							
						
					
					
						commit
						9b68ecb614
					
				| @ -1,6 +1,6 @@ | ||||
| // Main | ||||
| fn main() -> i32 { | ||||
|     return fibonacci(3); | ||||
|     return (fibonacci(3) < 5) + 5; | ||||
| } | ||||
| 
 | ||||
| // Fibonacci | ||||
|  | ||||
| @ -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!"), | ||||
|         } | ||||
|  | ||||
| @ -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)] | ||||
|  | ||||
| @ -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) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user