From 104205ee5db33a7f276d853f3bfb0ea190026527 Mon Sep 17 00:00:00 2001 From: sofia Date: Tue, 22 Jul 2025 13:24:53 +0300 Subject: [PATCH] Type-infer and check typecasting --- reid/src/mir/implement.rs | 202 ++++++++++++++++++++-------------- reid/src/mir/linker.rs | 2 +- reid/src/mir/typecheck.rs | 8 +- reid/src/mir/typeinference.rs | 5 +- reid/src/mir/typerefs.rs | 2 +- reid_src/cast.reid | 11 ++ 6 files changed, 142 insertions(+), 88 deletions(-) create mode 100644 reid_src/cast.reid diff --git a/reid/src/mir/implement.rs b/reid/src/mir/implement.rs index 989acc8..bc6a25d 100644 --- a/reid/src/mir/implement.rs +++ b/reid/src/mir/implement.rs @@ -14,6 +14,82 @@ pub enum ReturnTypeOther { } impl TypeKind { + pub fn collapse_into(&self, other: &TypeKind) -> Result { + if self == other { + return Ok(self.clone()); + } + + match (self, other) { + (TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => { + match other { + TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Integer)), + TypeKind::Vague(Vague::Integer) => Ok(TypeKind::Vague(Vague::Integer)), + TypeKind::I8 + | TypeKind::I16 + | TypeKind::I32 + | TypeKind::I64 + | TypeKind::I128 + | TypeKind::U8 + | TypeKind::U16 + | TypeKind::U32 + | TypeKind::U64 + | TypeKind::U128 => Ok(other.clone()), + _ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())), + } + } + (TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => { + match other { + TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Decimal)), + TypeKind::Vague(Vague::Decimal) => Ok(TypeKind::Vague(Vague::Decimal)), + TypeKind::F16 + | TypeKind::F32B + | TypeKind::F32 + | TypeKind::F64 + | TypeKind::F80 + | TypeKind::F128 + | TypeKind::F128PPC => Ok(other.clone()), + _ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())), + } + } + (TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => { + Ok(other.clone()) + } + (TypeKind::Borrow(val1, mut1), TypeKind::Borrow(val2, mut2)) => { + // Extracted to give priority for other collapse-error + let collapsed = val1.collapse_into(val2)?; + if mut1 == mut2 { + Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2)) + } else { + Err(ErrorKind::TypesDifferMutability( + self.clone(), + other.clone(), + )) + } + } + (TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => { + Ok(TypeKind::UserPtr(Box::new(val1.collapse_into(val2)?))) + } + _ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())), + } + } + + pub fn cast_into(&self, other: &TypeKind) -> Result { + if let Ok(collapsed) = self.collapse_into(other) { + Ok(collapsed) + } else { + let self_cat = self.category(); + let other_cat = other.category(); + match (self, other) { + (TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Ok(other.clone()), + _ => match (&self_cat, &other_cat) { + (TypeCategory::Integer, TypeCategory::Integer) => Ok(other.clone()), + (TypeCategory::Real, TypeCategory::Real) => Ok(other.clone()), + _ => Err(ErrorKind::NotCastableTo(self.clone(), other.clone())), + }, + } + } + } + /// 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 { @@ -159,6 +235,49 @@ impl TypeKind { _ => true, } } + + pub fn category(&self) -> TypeCategory { + match self { + TypeKind::I8 + | TypeKind::I16 + | TypeKind::I32 + | TypeKind::I64 + | TypeKind::I128 + | TypeKind::U8 + | TypeKind::U16 + | TypeKind::U32 + | TypeKind::U64 + | TypeKind::U128 + | TypeKind::Str => TypeCategory::Integer, + TypeKind::F16 + | TypeKind::F32B + | TypeKind::F32 + | TypeKind::F64 + | TypeKind::F128 + | TypeKind::F80 + | TypeKind::F128PPC => TypeCategory::Real, + TypeKind::Void => TypeCategory::Other, + TypeKind::Bool => TypeCategory::Other, + TypeKind::Array(_, _) => TypeCategory::Other, + TypeKind::CustomType(_) => TypeCategory::Other, + TypeKind::Borrow(_, _) => TypeCategory::Other, + TypeKind::UserPtr(_) => TypeCategory::Other, + TypeKind::CodegenPtr(_) => TypeCategory::Other, + TypeKind::Vague(vague_type) => match vague_type { + VagueType::Unknown => TypeCategory::Other, + VagueType::Integer => TypeCategory::Integer, + VagueType::Decimal => TypeCategory::Real, + VagueType::TypeRef(_) => TypeCategory::TypeRef, + }, + } + } +} + +pub enum TypeCategory { + Integer, + Real, + Other, + TypeRef, } impl StructType { @@ -467,73 +586,6 @@ impl TypeKind { } } -pub trait Collapsable: Sized + Clone { - /// Try to narrow two types into one singular type. E.g. Vague(Number) and - /// I32 could be narrowed to just I32. - fn collapse_into(&self, other: &Self) -> Result; -} - -impl Collapsable for TypeKind { - fn collapse_into(&self, other: &TypeKind) -> Result { - if self == other { - return Ok(self.clone()); - } - - match (self, other) { - (TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => { - match other { - TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Integer)), - TypeKind::Vague(Vague::Integer) => Ok(TypeKind::Vague(Vague::Integer)), - TypeKind::I8 - | TypeKind::I16 - | TypeKind::I32 - | TypeKind::I64 - | TypeKind::I128 - | TypeKind::U8 - | TypeKind::U16 - | TypeKind::U32 - | TypeKind::U64 - | TypeKind::U128 => Ok(other.clone()), - _ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())), - } - } - (TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => { - match other { - TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Decimal)), - TypeKind::Vague(Vague::Decimal) => Ok(TypeKind::Vague(Vague::Decimal)), - TypeKind::F16 - | TypeKind::F32B - | TypeKind::F32 - | TypeKind::F64 - | TypeKind::F80 - | TypeKind::F128 - | TypeKind::F128PPC => Ok(other.clone()), - _ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())), - } - } - (TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => { - Ok(other.clone()) - } - (TypeKind::Borrow(val1, mut1), TypeKind::Borrow(val2, mut2)) => { - // Extracted to give priority for other collapse-error - let collapsed = val1.collapse_into(val2)?; - if mut1 == mut2 { - Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2)) - } else { - Err(ErrorKind::TypesDifferMutability( - self.clone(), - other.clone(), - )) - } - } - (TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => { - Ok(TypeKind::UserPtr(Box::new(val1.collapse_into(val2)?))) - } - _ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())), - } - } -} - impl Literal { pub fn num_value(&self) -> Option { match self { @@ -562,22 +614,6 @@ impl Literal { } } -impl Collapsable for ScopeFunction { - fn collapse_into(&self, other: &ScopeFunction) -> Result { - Ok(ScopeFunction { - ret: self.ret.collapse_into(&other.ret)?, - params: try_all( - self.params - .iter() - .zip(&other.params) - .map(|(p1, p2)| p1.collapse_into(&p2)) - .collect(), - ) - .map_err(|e| e.first().unwrap().clone())?, - }) - } -} - #[derive(Debug, Clone, thiserror::Error, PartialEq, Eq, PartialOrd, Ord)] pub enum EqualsIssue { #[error("Function is already defined locally at {:?}", (.0).range)] diff --git a/reid/src/mir/linker.rs b/reid/src/mir/linker.rs index 7704666..3484c21 100644 --- a/reid/src/mir/linker.rs +++ b/reid/src/mir/linker.rs @@ -72,7 +72,7 @@ impl<'map> Pass for LinkerPass<'map> { type Data = (); type TError = ErrorKind; fn context(&mut self, context: &mut Context, mut state: LinkerPassState) -> PassResult { - let mut mains = context + let mains = context .modules .iter_mut() .filter(|m| m.is_main) diff --git a/reid/src/mir/typecheck.rs b/reid/src/mir/typecheck.rs index 28f4e4a..7978b8e 100644 --- a/reid/src/mir/typecheck.rs +++ b/reid/src/mir/typecheck.rs @@ -6,7 +6,6 @@ use crate::{mir::*, util::try_all}; use VagueType as Vague; use super::{ - implement::Collapsable, pass::{Pass, PassResult, PassState, ScopeVariable}, typerefs::TypeRefs, }; @@ -67,6 +66,8 @@ pub enum ErrorKind { ImpossibleMutLet(String), #[error("Cannot produce a negative unsigned value of type {0}!")] NegativeUnsignedValue(TypeKind), + #[error("Cannot cast type {0} into type {1}!")] + NotCastableTo(TypeKind, TypeKind), } /// Struct used to implement a type-checking pass that can be performed on the @@ -712,7 +713,10 @@ impl Expression { Ok(*inner) } - ExprKind::CastTo(expression, type_kind) => todo!(), + ExprKind::CastTo(expression, type_kind) => { + let expr = expression.typecheck(state, typerefs, None)?; + expr.resolve_ref(typerefs).cast_into(type_kind) + } } } } diff --git a/reid/src/mir/typeinference.rs b/reid/src/mir/typeinference.rs index 580167d..e154941 100644 --- a/reid/src/mir/typeinference.rs +++ b/reid/src/mir/typeinference.rs @@ -397,7 +397,10 @@ impl Expression { _ => Err(ErrorKind::AttemptedDerefNonBorrow(var.1.clone())), } } - ExprKind::CastTo(expression, type_kind) => todo!(), + ExprKind::CastTo(expression, type_kind) => { + expression.infer_types(state, type_refs)?; + Ok(type_refs.from_type(type_kind).unwrap()) + } } } } diff --git a/reid/src/mir/typerefs.rs b/reid/src/mir/typerefs.rs index 729c87c..2e6586d 100644 --- a/reid/src/mir/typerefs.rs +++ b/reid/src/mir/typerefs.rs @@ -6,7 +6,7 @@ use std::{ use crate::mir::VagueType; -use super::{implement::Collapsable, typecheck::ErrorKind, BinaryOperator, TypeKind}; +use super::{typecheck::ErrorKind, BinaryOperator, TypeKind}; #[derive(Clone)] pub struct TypeRef<'scope>(TypeIdRef, &'scope ScopeTypeRefs<'scope>); diff --git a/reid_src/cast.reid b/reid_src/cast.reid new file mode 100644 index 0000000..7f3c60f --- /dev/null +++ b/reid_src/cast.reid @@ -0,0 +1,11 @@ +// Arithmetic, function calls and imports! + +fn other() -> u16 { + return 6; +} + +fn main() -> u32 { + let value = other() as u32; + + return value; +}