diff --git a/reid/src/ast/process.rs b/reid/src/ast/process.rs index 3667bb4..44cb533 100644 --- a/reid/src/ast/process.rs +++ b/reid/src/ast/process.rs @@ -44,8 +44,6 @@ impl ast::Module { } } - // TODO do something with state here - mir::Module { name: self.name.clone(), imports, diff --git a/reid/src/mir/typecheck.rs b/reid/src/mir/typecheck.rs index 18f33e3..46e7b2f 100644 --- a/reid/src/mir/typecheck.rs +++ b/reid/src/mir/typecheck.rs @@ -38,6 +38,8 @@ pub enum ErrorKind { InvalidAmountParameters(String, usize, usize), #[error("Unable to infer type {0}")] TypeNotInferrable(TypeKind), + #[error("Expected branch type to be {0}, found {1} instead")] + BranchTypesDiffer(TypeKind, TypeKind), } /// Struct used to implement a type-checking pass that can be performed on the @@ -118,7 +120,7 @@ impl Block { let res = expression.typecheck(&mut state, &hints, Some(var_t_resolved)); // If expression resolution itself was erronous, resolve as - // Unknown. + // Unknown and note error. let res = state.or_else(res, Vague(Unknown), expression.1); // Make sure the expression and variable type really is the same @@ -286,8 +288,8 @@ impl Expression { rhs.typecheck(state, &hints, Some(collapsed)).ok(); } - let res = lhs_type.binop_type(&op, &rhs_type)?; - Ok(res) + let both_t = lhs_type.collapse_into(&rhs_type)?; + Ok(both_t.binop_type(op)) } ExprKind::FunctionCall(function_call) => { let true_function = state @@ -338,7 +340,6 @@ impl Expression { } } ExprKind::If(IfExpression(cond, lhs, rhs)) => { - // TODO make sure cond_res is Boolean here let cond_res = cond.typecheck(state, &hints, Some(Bool)); let cond_t = state.or_else(cond_res, Vague(Unknown), cond.1); state.ok(cond_t.collapse_into(&Bool), cond.1); @@ -351,11 +352,15 @@ impl Expression { let res = else_block.typecheck(state, &hints, hint_t); state.or_else(res, Vague(Unknown), else_block.meta) } else { - // TODO assert that then_ret_t is Void - Vague(Unknown) + // Else return type is Void if it does not exist + Void }; - let collapsed = then_ret_t.collapse_into(&else_ret_t)?; + // Make sure then and else -blocks have the same return type + let collapsed = then_ret_t + .collapse_into(&else_ret_t) + .or(Err(ErrorKind::BranchTypesDiffer(then_ret_t, else_ret_t)))?; + if let Some(rhs) = rhs { // If rhs existed, typecheck both sides to perform type // coercion. @@ -391,6 +396,8 @@ impl Literal { (L::U64(_), U64) => self, (L::U128(_), U128) => self, (L::Bool(_), Bool) => self, + // TODO make sure that v is actually able to fit in the + // requested type (L::Vague(VagueL::Number(v)), I8) => L::I8(v as i8), (L::Vague(VagueL::Number(v)), I16) => L::I16(v as i16), (L::Vague(VagueL::Number(v)), I32) => L::I32(v as i32), @@ -430,17 +437,6 @@ impl TypeKind { } } - fn binop_type(&self, op: &BinaryOperator, other: &TypeKind) -> Result { - let res = self.collapse_into(other)?; - Ok(match op { - BinaryOperator::Add => res, - BinaryOperator::Minus => res, - BinaryOperator::Mult => res, - BinaryOperator::And => res, - BinaryOperator::Cmp(_) => Bool, - }) - } - fn resolve_hinted(&self, hints: &TypeRefs) -> TypeKind { match self { Vague(TypeRef(idx)) => hints.retrieve_type(*idx).unwrap(), diff --git a/reid/src/mir/typerefs.rs b/reid/src/mir/typerefs.rs index 81fb400..cbad7ab 100644 --- a/reid/src/mir/typerefs.rs +++ b/reid/src/mir/typerefs.rs @@ -194,12 +194,6 @@ impl<'outer> ScopeTypeRefs<'outer> { rhs: &mut TypeRef<'outer>, ) -> Option> { let ty = lhs.narrow(rhs)?; - Some(match op { - BinaryOperator::Add => ty, - BinaryOperator::Minus => ty, - BinaryOperator::Mult => ty, - BinaryOperator::And => self.from_type(&TypeKind::Bool).unwrap(), - BinaryOperator::Cmp(_) => self.from_type(&TypeKind::Bool).unwrap(), - }) + self.from_type(&ty.as_type().binop_type(op)) } } diff --git a/reid/src/mir/types.rs b/reid/src/mir/types.rs index ba9c8ff..5d96293 100644 --- a/reid/src/mir/types.rs +++ b/reid/src/mir/types.rs @@ -9,7 +9,24 @@ pub enum ReturnTypeOther { NoBlockReturn(Metadata), } +impl TypeKind { + /// Return the type that is the result of a binary operator between two + /// values of this type + pub fn binop_type(&self, op: &BinaryOperator) -> TypeKind { + // TODO make some type of mechanism that allows to binop two values of + // differing types.. + match op { + BinaryOperator::Add => *self, + BinaryOperator::Minus => *self, + BinaryOperator::Mult => *self, + BinaryOperator::And => TypeKind::Bool, + BinaryOperator::Cmp(_) => TypeKind::Bool, + } + } +} + pub trait ReturnType { + /// Return the return type of this node fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther>; } @@ -24,9 +41,6 @@ impl ReturnType for Block { } } - // TODO should actually probably prune all instructions after this one - // as to not cause problems in codegen later (when unable to delete the - // block) if let Some((ReturnKind::Hard, ret_ty)) = early_return { return Ok((ReturnKind::Hard, ret_ty)); }