Move binop type resolution to common implementation
This commit is contained in:
parent
a8ed7577a8
commit
4e8228f903
@ -44,8 +44,6 @@ impl ast::Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO do something with state here
|
|
||||||
|
|
||||||
mir::Module {
|
mir::Module {
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
imports,
|
imports,
|
||||||
|
@ -38,6 +38,8 @@ pub enum ErrorKind {
|
|||||||
InvalidAmountParameters(String, usize, usize),
|
InvalidAmountParameters(String, usize, usize),
|
||||||
#[error("Unable to infer type {0}")]
|
#[error("Unable to infer type {0}")]
|
||||||
TypeNotInferrable(TypeKind),
|
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
|
/// 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));
|
let res = expression.typecheck(&mut state, &hints, Some(var_t_resolved));
|
||||||
|
|
||||||
// If expression resolution itself was erronous, resolve as
|
// If expression resolution itself was erronous, resolve as
|
||||||
// Unknown.
|
// Unknown and note error.
|
||||||
let res = state.or_else(res, Vague(Unknown), expression.1);
|
let res = state.or_else(res, Vague(Unknown), expression.1);
|
||||||
|
|
||||||
// Make sure the expression and variable type really is the same
|
// Make sure the expression and variable type really is the same
|
||||||
@ -286,8 +288,8 @@ impl Expression {
|
|||||||
rhs.typecheck(state, &hints, Some(collapsed)).ok();
|
rhs.typecheck(state, &hints, Some(collapsed)).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = lhs_type.binop_type(&op, &rhs_type)?;
|
let both_t = lhs_type.collapse_into(&rhs_type)?;
|
||||||
Ok(res)
|
Ok(both_t.binop_type(op))
|
||||||
}
|
}
|
||||||
ExprKind::FunctionCall(function_call) => {
|
ExprKind::FunctionCall(function_call) => {
|
||||||
let true_function = state
|
let true_function = state
|
||||||
@ -338,7 +340,6 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
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_res = cond.typecheck(state, &hints, Some(Bool));
|
||||||
let cond_t = state.or_else(cond_res, Vague(Unknown), cond.1);
|
let cond_t = state.or_else(cond_res, Vague(Unknown), cond.1);
|
||||||
state.ok(cond_t.collapse_into(&Bool), 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);
|
let res = else_block.typecheck(state, &hints, hint_t);
|
||||||
state.or_else(res, Vague(Unknown), else_block.meta)
|
state.or_else(res, Vague(Unknown), else_block.meta)
|
||||||
} else {
|
} else {
|
||||||
// TODO assert that then_ret_t is Void
|
// Else return type is Void if it does not exist
|
||||||
Vague(Unknown)
|
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 let Some(rhs) = rhs {
|
||||||
// If rhs existed, typecheck both sides to perform type
|
// If rhs existed, typecheck both sides to perform type
|
||||||
// coercion.
|
// coercion.
|
||||||
@ -391,6 +396,8 @@ impl Literal {
|
|||||||
(L::U64(_), U64) => self,
|
(L::U64(_), U64) => self,
|
||||||
(L::U128(_), U128) => self,
|
(L::U128(_), U128) => self,
|
||||||
(L::Bool(_), Bool) => 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)), I8) => L::I8(v as i8),
|
||||||
(L::Vague(VagueL::Number(v)), I16) => L::I16(v as i16),
|
(L::Vague(VagueL::Number(v)), I16) => L::I16(v as i16),
|
||||||
(L::Vague(VagueL::Number(v)), I32) => L::I32(v as i32),
|
(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<TypeKind, ErrorKind> {
|
|
||||||
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 {
|
fn resolve_hinted(&self, hints: &TypeRefs) -> TypeKind {
|
||||||
match self {
|
match self {
|
||||||
Vague(TypeRef(idx)) => hints.retrieve_type(*idx).unwrap(),
|
Vague(TypeRef(idx)) => hints.retrieve_type(*idx).unwrap(),
|
||||||
|
@ -194,12 +194,6 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
|||||||
rhs: &mut TypeRef<'outer>,
|
rhs: &mut TypeRef<'outer>,
|
||||||
) -> Option<TypeRef<'outer>> {
|
) -> Option<TypeRef<'outer>> {
|
||||||
let ty = lhs.narrow(rhs)?;
|
let ty = lhs.narrow(rhs)?;
|
||||||
Some(match op {
|
self.from_type(&ty.as_type().binop_type(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(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,24 @@ pub enum ReturnTypeOther {
|
|||||||
NoBlockReturn(Metadata),
|
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 {
|
pub trait ReturnType {
|
||||||
|
/// Return the return type of this node
|
||||||
fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther>;
|
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 {
|
if let Some((ReturnKind::Hard, ret_ty)) = early_return {
|
||||||
return Ok((ReturnKind::Hard, ret_ty));
|
return Ok((ReturnKind::Hard, ret_ty));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user