From f8d2e4996a458256dba26afc83ceeede0882f433 Mon Sep 17 00:00:00 2001 From: sofia Date: Fri, 25 Jul 2025 16:15:50 +0300 Subject: [PATCH] Refactor typecheck into it's own module --- reid/src/error_raporting.rs | 12 +- reid/src/lib.rs | 3 +- reid/src/mir/fmt.rs | 19 +- reid/src/mir/implement.rs | 174 ++----------- reid/src/mir/mod.rs | 2 - reid/src/mir/typecheck/mod.rs | 241 ++++++++++++++++++ reid/src/mir/{ => typecheck}/typecheck.rs | 101 +------- reid/src/mir/{ => typecheck}/typeinference.rs | 37 +-- reid/src/mir/{ => typecheck}/typerefs.rs | 28 +- reid/src/util.rs | 11 + 10 files changed, 325 insertions(+), 303 deletions(-) create mode 100644 reid/src/mir/typecheck/mod.rs rename reid/src/mir/{ => typecheck}/typecheck.rs (89%) rename reid/src/mir/{ => typecheck}/typeinference.rs (96%) rename reid/src/mir/{ => typecheck}/typerefs.rs (91%) diff --git a/reid/src/error_raporting.rs b/reid/src/error_raporting.rs index 16070e8..f1ff41e 100644 --- a/reid/src/error_raporting.rs +++ b/reid/src/error_raporting.rs @@ -7,9 +7,11 @@ use crate::{ ast::token_stream::{self, TokenRange}, codegen, lexer::{self, Cursor, FullToken, Position}, - mir::{self, pass, Metadata, SourceModuleId}, + mir::{self, pass, typecheck, Metadata, SourceModuleId}, }; +use crate::mir::typecheck::ErrorKind as TypecheckError; + fn label(text: &str) -> &str { #[cfg(debug_assertions)] { @@ -26,9 +28,9 @@ pub enum ErrorKind { #[error("{}{}", label("(Parsing) "), .0.kind)] ParserError(#[from] mir::pass::Error), #[error("{}{}", label("(TypeCheck) "), .0.kind)] - TypeCheckError(#[source] mir::pass::Error), + TypeCheckError(#[source] mir::pass::Error), #[error("{}{}", label("(TypeInference) "), .0.kind)] - TypeInferenceError(#[source] mir::pass::Error), + TypeInferenceError(#[source] mir::pass::Error), #[error("{}{}", label("(Linker) "), .0.kind)] LinkerError(#[from] mir::pass::Error), #[error("{}{}", label("(Codegen) "), .0)] @@ -36,11 +38,11 @@ pub enum ErrorKind { } impl ErrorKind { - pub fn from_typecheck(err: mir::pass::Error) -> ErrorKind { + pub fn from_typecheck(err: mir::pass::Error) -> ErrorKind { ErrorKind::TypeCheckError(err) } - pub fn from_typeinference(err: mir::pass::Error) -> ErrorKind { + pub fn from_typeinference(err: mir::pass::Error) -> ErrorKind { ErrorKind::TypeInferenceError(err) } } diff --git a/reid/src/lib.rs b/reid/src/lib.rs index ade689f..9c58b59 100644 --- a/reid/src/lib.rs +++ b/reid/src/lib.rs @@ -50,7 +50,8 @@ use ast::{ use codegen::intrinsics::{form_intrinsic_binops, form_intrinsics}; use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError}; use mir::{ - linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs, + linker::LinkerPass, + typecheck::{typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs}, }; use reid_lib::{compile::CompileOutput, Context}; diff --git a/reid/src/mir/fmt.rs b/reid/src/mir/fmt.rs index 5b86600..ce8fe9a 100644 --- a/reid/src/mir/fmt.rs +++ b/reid/src/mir/fmt.rs @@ -2,24 +2,7 @@ use std::fmt::{Debug, Display, Write}; use crate::pad_adapter::PadAdapter; -use super::{typerefs::TypeRefs, *}; - -impl Display for TypeRefs { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for (i, typeref) in self.type_refs.borrow().iter().enumerate() { - let idx = *typeref.borrow(); - writeln!( - f, - "{:<3} = {:<3} = {:?} = {}", - i, - unsafe { *self.recurse_type_ref(idx).borrow() }, - self.retrieve_type(idx), - TypeKind::Vague(VagueType::TypeRef(idx)).resolve_ref(self) - )?; - } - Ok(()) - } -} +use super::{typecheck::typerefs::TypeRefs, *}; impl Display for Context { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/reid/src/mir/implement.rs b/reid/src/mir/implement.rs index a80bf54..5b3c162 100644 --- a/reid/src/mir/implement.rs +++ b/reid/src/mir/implement.rs @@ -1,4 +1,6 @@ -use super::{pass::ScopeBinopDef, typecheck::ErrorKind, typerefs::TypeRefs, VagueType as Vague, *}; +use crate::util::maybe; + +use super::{pass::ScopeBinopDef, typecheck::typerefs::TypeRefs, *}; #[derive(Debug, Clone)] pub enum ReturnTypeOther { @@ -12,87 +14,18 @@ pub enum ReturnTypeOther { Loop, } +#[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)] +pub enum NumValueError { + #[error("Cannot divide by zero")] + DivideZero, +} + +enum BlockReturn<'b> { + Early(&'b Statement), + Normal(ReturnKind, &'b Option>), +} + 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()), - (TypeKind::Char, TypeKind::U8) => Ok(other.clone()), - (TypeKind::U8, TypeKind::Char) => Ok(other.clone()), - _ => match (&self_cat, &other_cat) { - (TypeCategory::Integer, TypeCategory::Integer) => Ok(other.clone()), - (TypeCategory::Integer, TypeCategory::Real) => Ok(other.clone()), - (TypeCategory::Real, 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 simple_binop_type(&self, op: &BinaryOperator) -> Option { @@ -365,11 +298,6 @@ impl StructType { } } -enum BlockReturn<'b> { - Early(&'b Statement), - Normal(ReturnKind, &'b Option>), -} - impl Block { fn return_expr(&self) -> Result { let mut early_return = None; @@ -566,15 +494,7 @@ impl Expression { } } - pub fn is_zero(&self) -> Result, ErrorKind> { - if let Some(val) = self.num_value()? { - Ok(Some(val == 0)) - } else { - Ok(None) - } - } - - pub fn num_value(&self) -> Result, ErrorKind> { + pub fn num_value(&self) -> Result, NumValueError> { Ok(match &self.0 { ExprKind::Variable(_) => None, ExprKind::Indexed(..) => None, @@ -591,14 +511,14 @@ impl Expression { BinaryOperator::Div => { let rhs_value = rhs.num_value()?; if rhs_value == Some(0) { - Err(ErrorKind::DivideZero)? + Err(NumValueError::DivideZero)? } maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a / b) } BinaryOperator::Mod => { let rhs_value = rhs.num_value()?; if rhs_value == Some(0) { - Err(ErrorKind::DivideZero)? + Err(NumValueError::DivideZero)? } maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a % b) } @@ -613,16 +533,6 @@ impl Expression { } } -fn maybe(lhs: Option, rhs: Option, fun: T) -> Option -where - T: FnOnce(i128, i128) -> i128, -{ - if let (Some(lhs), Some(rhs)) = (lhs, rhs) { - Some(fun(lhs, rhs)) - } else { - None - } -} impl IfExpression { pub fn return_type( &self, @@ -678,56 +588,6 @@ pub fn pick_return(lhs: (ReturnKind, T), rhs: (ReturnKind, T)) -> (ReturnKind } } -impl TypeKind { - /// Assert that a type is already known and not vague. Return said type or - /// error. - pub fn assert_unvague(&self) -> Result { - self.known().map_err(ErrorKind::TypeIsVague) - } - - /// Try to collapse a type on itself producing a default type if one exists, - /// Error if not. - pub fn or_default(&self) -> Result { - Ok(match self { - TypeKind::Vague(vague_type) => match &vague_type { - Vague::Unknown => Err(ErrorKind::TypeIsVague(*vague_type))?, - Vague::Integer => TypeKind::I32, - Vague::TypeRef(_) => panic!("Hinted default!"), - VagueType::Decimal => TypeKind::F32, - }, - TypeKind::Array(type_kind, len) => { - TypeKind::Array(Box::new(type_kind.or_default()?), *len) - } - TypeKind::Borrow(type_kind, mutable) => { - TypeKind::Borrow(Box::new(type_kind.or_default()?), *mutable) - } - TypeKind::UserPtr(type_kind) => TypeKind::UserPtr(Box::new(type_kind.or_default()?)), - TypeKind::CodegenPtr(type_kind) => { - TypeKind::CodegenPtr(Box::new(type_kind.or_default()?)) - } - _ => self.clone(), - }) - } - - pub fn resolve_weak(&self, refs: &TypeRefs) -> TypeKind { - match self { - TypeKind::Vague(Vague::TypeRef(idx)) => refs.retrieve_type(*idx).unwrap(), - _ => self.clone(), - } - } - - pub fn resolve_ref(&self, refs: &TypeRefs) -> TypeKind { - let resolved = self.resolve_weak(refs); - match resolved { - TypeKind::Array(t, len) => TypeKind::Array(Box::new(t.resolve_ref(refs)), len), - TypeKind::Borrow(inner, mutable) => { - TypeKind::Borrow(Box::new(inner.resolve_ref(refs)), mutable) - } - _ => resolved, - } - } -} - impl Literal { pub fn num_value(&self) -> Option { match self { diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index 315f2ac..86d039a 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -15,8 +15,6 @@ pub mod implement; pub mod linker; pub mod pass; pub mod typecheck; -pub mod typeinference; -pub mod typerefs; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] pub struct SourceModuleId(pub u32); diff --git a/reid/src/mir/typecheck/mod.rs b/reid/src/mir/typecheck/mod.rs new file mode 100644 index 0000000..78b41d5 --- /dev/null +++ b/reid/src/mir/typecheck/mod.rs @@ -0,0 +1,241 @@ +use crate::mir::VagueType as Vague; +use crate::mir::*; +use typecheck::ErrorTypedefKind; +use typerefs::TypeRefs; + +use super::implement::{NumValueError, TypeCategory}; +use super::pass::PassState; + +pub mod typecheck; +pub mod typeinference; +pub mod typerefs; + +pub type TypecheckPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>; + +#[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)] +pub enum ErrorKind { + #[error("NULL error, should never occur!")] + Null, + #[error("Type is vague: {0}")] + TypeIsVague(VagueType), + #[error("Literal {0} can not be coerced to type {1}")] + LiteralIncompatible(Literal, TypeKind), + #[error("Types {0} and {1} are incompatible")] + TypesIncompatible(TypeKind, TypeKind), + #[error("Variable not defined: {0}")] + VariableNotDefined(String), + #[error("Function not defined: {0}")] + FunctionNotDefined(String), + #[error("Expected a return type of {0}, got {1} instead")] + ReturnTypeMismatch(TypeKind, TypeKind), + #[error("Function {0} already defined {1}")] + FunctionAlreadyDefined(String, ErrorTypedefKind), + #[error("Variable already defined: {0}")] + VariableAlreadyDefined(String), + #[error("Variable {0} is not declared as mutable")] + VariableNotMutable(String), + #[error("Function {0} was given {1} parameters, but {2} were expected")] + 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), + #[error("Attempted to index a non-indexable type of {0}")] + TriedIndexingNonIndexable(TypeKind), + #[error("Index {0} out of bounds ({1})")] + IndexOutOfBounds(u64, u64), + #[error("No such type {0} could be found in module {1}")] + NoSuchType(String, SourceModuleId), + #[error("Attempted to access field of non-struct type of {0}")] + TriedAccessingNonStruct(TypeKind), + #[error("No such struct-field on type {0}")] + NoSuchField(String), + #[error("Struct field declared twice {0}")] + DuplicateStructField(String), + #[error("Type declared twice {0}")] + DuplicateTypeName(String), + #[error("Recursive type definition: {0}.{1}")] + RecursiveTypeDefinition(String, String), + #[error("This type of expression can not be used for assignment")] + InvalidSetExpression, + #[error("Can not deref {0}, as it is not a borrow")] + AttemptedDerefNonBorrow(String), + #[error("Types {0} and {1} differ in mutability")] + TypesDifferMutability(TypeKind, TypeKind), + #[error("Cannot mutably borrow variable {0}, which is not declared as mutable")] + ImpossibleMutableBorrow(String), + #[error("Cannot declare variable {0} as mutable, when it's type is immutable")] + 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), + #[error(transparent)] + NumValueError(#[from] NumValueError), + #[error("Binary operation {0} between {1} and {2} is already defined")] + BinaryOpAlreadyDefined(BinaryOperator, TypeKind, TypeKind), + #[error("Binary operation {0} between {1} and {2} is not defined")] + InvalidBinop(BinaryOperator, TypeKind, TypeKind), +} + +impl TypeKind { + pub(super) 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(super) 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()), + (TypeKind::Char, TypeKind::U8) => Ok(other.clone()), + (TypeKind::U8, TypeKind::Char) => Ok(other.clone()), + _ => match (&self_cat, &other_cat) { + (TypeCategory::Integer, TypeCategory::Integer) => Ok(other.clone()), + (TypeCategory::Integer, TypeCategory::Real) => Ok(other.clone()), + (TypeCategory::Real, TypeCategory::Integer) => Ok(other.clone()), + (TypeCategory::Real, TypeCategory::Real) => Ok(other.clone()), + _ => Err(ErrorKind::NotCastableTo(self.clone(), other.clone())), + }, + } + } + } + + /// Assert that a type is already known and not vague. Return said type or + /// error. + pub(super) fn assert_unvague(&self) -> Result { + self.known().map_err(ErrorKind::TypeIsVague) + } + + /// Try to collapse a type on itself producing a default type if one exists, + /// Error if not. + pub(super) fn or_default(&self) -> Result { + Ok(match self { + TypeKind::Vague(vague_type) => match &vague_type { + Vague::Unknown => Err(ErrorKind::TypeIsVague(*vague_type))?, + Vague::Integer => TypeKind::I32, + Vague::TypeRef(_) => panic!("Hinted default!"), + VagueType::Decimal => TypeKind::F32, + }, + TypeKind::Array(type_kind, len) => { + TypeKind::Array(Box::new(type_kind.or_default()?), *len) + } + TypeKind::Borrow(type_kind, mutable) => { + TypeKind::Borrow(Box::new(type_kind.or_default()?), *mutable) + } + TypeKind::UserPtr(type_kind) => TypeKind::UserPtr(Box::new(type_kind.or_default()?)), + TypeKind::CodegenPtr(type_kind) => { + TypeKind::CodegenPtr(Box::new(type_kind.or_default()?)) + } + _ => self.clone(), + }) + } + + pub(super) fn resolve_weak(&self, refs: &TypeRefs) -> TypeKind { + match self { + TypeKind::Vague(Vague::TypeRef(idx)) => refs.retrieve_type(*idx).unwrap(), + _ => self.clone(), + } + } + + pub(super) fn resolve_ref(&self, refs: &TypeRefs) -> TypeKind { + let resolved = self.resolve_weak(refs); + match resolved { + TypeKind::Array(t, len) => TypeKind::Array(Box::new(t.resolve_ref(refs)), len), + TypeKind::Borrow(inner, mutable) => { + TypeKind::Borrow(Box::new(inner.resolve_ref(refs)), mutable) + } + _ => resolved, + } + } + + pub(super) fn assert_known( + &self, + refs: &TypeRefs, + state: &TypecheckPassState, + ) -> Result { + self.is_known(refs, state).map(|_| self.clone()) + } + + pub(super) fn is_known( + &self, + refs: &TypeRefs, + state: &TypecheckPassState, + ) -> Result<(), ErrorKind> { + match &self { + TypeKind::Array(type_kind, _) => type_kind.as_ref().is_known(refs, state), + TypeKind::CustomType(custom_type_key) => state + .scope + .types + .get(custom_type_key) + .map(|_| ()) + .ok_or(ErrorKind::NoSuchType( + custom_type_key.0.clone(), + state.module_id.unwrap(), + )), + TypeKind::Borrow(type_kind, _) => type_kind.is_known(refs, state), + TypeKind::UserPtr(type_kind) => type_kind.is_known(refs, state), + TypeKind::CodegenPtr(type_kind) => type_kind.is_known(refs, state), + TypeKind::Vague(vague_type) => Err(ErrorKind::TypeIsVague(*vague_type)), + _ => Ok(()), + } + } +} diff --git a/reid/src/mir/typecheck.rs b/reid/src/mir/typecheck/typecheck.rs similarity index 89% rename from reid/src/mir/typecheck.rs rename to reid/src/mir/typecheck/typecheck.rs index 1fa47df..0b76d03 100644 --- a/reid/src/mir/typecheck.rs +++ b/reid/src/mir/typecheck/typecheck.rs @@ -6,84 +6,17 @@ use crate::{mir::*, util::try_all}; use VagueType as Vague; use super::{ - pass::{Pass, PassResult, PassState, ScopeVariable}, + super::pass::{Pass, PassResult, ScopeVariable}, typerefs::TypeRefs, + ErrorKind, TypecheckPassState, }; -#[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)] -pub enum ErrorKind { - #[error("NULL error, should never occur!")] - Null, - #[error("Type is vague: {0}")] - TypeIsVague(VagueType), - #[error("Literal {0} can not be coerced to type {1}")] - LiteralIncompatible(Literal, TypeKind), - #[error("Types {0} and {1} are incompatible")] - TypesIncompatible(TypeKind, TypeKind), - #[error("Variable not defined: {0}")] - VariableNotDefined(String), - #[error("Function not defined: {0}")] - FunctionNotDefined(String), - #[error("Expected a return type of {0}, got {1} instead")] - ReturnTypeMismatch(TypeKind, TypeKind), - #[error("Function {0} already defined {1}")] - FunctionAlreadyDefined(String, ErrorTypedefKind), - #[error("Variable already defined: {0}")] - VariableAlreadyDefined(String), - #[error("Variable {0} is not declared as mutable")] - VariableNotMutable(String), - #[error("Function {0} was given {1} parameters, but {2} were expected")] - 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), - #[error("Attempted to index a non-indexable type of {0}")] - TriedIndexingNonIndexable(TypeKind), - #[error("Index {0} out of bounds ({1})")] - IndexOutOfBounds(u64, u64), - #[error("No such type {0} could be found in module {1}")] - NoSuchType(String, SourceModuleId), - #[error("Attempted to access field of non-struct type of {0}")] - TriedAccessingNonStruct(TypeKind), - #[error("No such struct-field on type {0}")] - NoSuchField(String), - #[error("Struct field declared twice {0}")] - DuplicateStructField(String), - #[error("Type declared twice {0}")] - DuplicateTypeName(String), - #[error("Recursive type definition: {0}.{1}")] - RecursiveTypeDefinition(String, String), - #[error("This type of expression can not be used for assignment")] - InvalidSetExpression, - #[error("Can not deref {0}, as it is not a borrow")] - AttemptedDerefNonBorrow(String), - #[error("Types {0} and {1} differ in mutability")] - TypesDifferMutability(TypeKind, TypeKind), - #[error("Cannot mutably borrow variable {0}, which is not declared as mutable")] - ImpossibleMutableBorrow(String), - #[error("Cannot declare variable {0} as mutable, when it's type is immutable")] - 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), - #[error("Cannot divide by zero")] - DivideZero, - #[error("Binary operation {0} between {1} and {2} is already defined")] - BinaryOpAlreadyDefined(BinaryOperator, TypeKind, TypeKind), - #[error("Binary operation {0} between {1} and {2} is not defined")] - InvalidBinop(BinaryOperator, TypeKind, TypeKind), -} - /// Struct used to implement a type-checking pass that can be performed on the /// MIR. pub struct TypeCheck<'t> { pub refs: &'t TypeRefs, } -type TypecheckPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>; - #[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum ErrorTypedefKind { #[error("locally")] @@ -920,32 +853,4 @@ impl Literal { } } -impl TypeKind { - fn assert_known( - &self, - refs: &TypeRefs, - state: &TypecheckPassState, - ) -> Result { - self.is_known(refs, state).map(|_| self.clone()) - } - - fn is_known(&self, refs: &TypeRefs, state: &TypecheckPassState) -> Result<(), ErrorKind> { - match &self { - TypeKind::Array(type_kind, _) => type_kind.as_ref().is_known(refs, state), - TypeKind::CustomType(custom_type_key) => state - .scope - .types - .get(custom_type_key) - .map(|_| ()) - .ok_or(ErrorKind::NoSuchType( - custom_type_key.0.clone(), - state.module_id.unwrap(), - )), - TypeKind::Borrow(type_kind, _) => type_kind.is_known(refs, state), - TypeKind::UserPtr(type_kind) => type_kind.is_known(refs, state), - TypeKind::CodegenPtr(type_kind) => type_kind.is_known(refs, state), - TypeKind::Vague(vague_type) => Err(ErrorKind::TypeIsVague(*vague_type)), - _ => Ok(()), - } - } -} +impl TypeKind {} diff --git a/reid/src/mir/typeinference.rs b/reid/src/mir/typecheck/typeinference.rs similarity index 96% rename from reid/src/mir/typeinference.rs rename to reid/src/mir/typecheck/typeinference.rs index 6cec876..c87aa95 100644 --- a/reid/src/mir/typeinference.rs +++ b/reid/src/mir/typecheck/typeinference.rs @@ -10,17 +10,24 @@ use std::{ iter, }; -use crate::{mir::TypeKind, util::try_all}; +use crate::{ + mir::{ + BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, + FunctionDefinitionKind, IfExpression, Module, ReturnKind, StmtKind, TypeKind, + WhileStatement, + }, + util::try_all, +}; use super::{ - pass::{Pass, PassResult, PassState, ScopeBinopKey}, - typecheck::{ErrorKind, ErrorTypedefKind}, + super::{ + pass::{Pass, PassResult, PassState, ScopeBinopKey}, + TypeKind::*, + VagueType::*, + }, + typecheck::ErrorTypedefKind, typerefs::{ScopeTypeRefs, TypeRef, TypeRefs}, - BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, - FunctionDefinitionKind, IfExpression, Module, ReturnKind, StmtKind, - TypeKind::*, - VagueType::*, - WhileStatement, + ErrorKind, TypecheckPassState, }; /// Struct used to implement Type Inference, where an intermediary @@ -30,13 +37,11 @@ pub struct TypeInference<'t> { pub refs: &'t TypeRefs, } -type TypeInferencePassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>; - impl<'t> Pass for TypeInference<'t> { type Data = (); type TError = ErrorKind; - fn module(&mut self, module: &mut Module, mut state: TypeInferencePassState) -> PassResult { + fn module(&mut self, module: &mut Module, mut state: TypecheckPassState) -> PassResult { let mut seen_functions = HashMap::new(); for function in &mut module.functions { if let Some(kind) = seen_functions.get(&function.name) { @@ -98,7 +103,7 @@ impl BinopDefinition { fn infer_types( &mut self, type_refs: &TypeRefs, - state: &mut TypeInferencePassState, + state: &mut TypecheckPassState, ) -> Result<(), ErrorKind> { let scope_hints = ScopeTypeRefs::from(type_refs); @@ -142,7 +147,7 @@ impl FunctionDefinition { fn infer_types( &mut self, type_refs: &TypeRefs, - state: &mut TypeInferencePassState, + state: &mut TypecheckPassState, ) -> Result<(), ErrorKind> { let scope_refs = ScopeTypeRefs::from(type_refs); for param in &self.parameters { @@ -183,7 +188,7 @@ impl FunctionDefinition { impl FunctionDefinitionKind { fn infer_types<'s>( &mut self, - state: &mut TypeInferencePassState, + state: &mut TypecheckPassState, scope_refs: &'s ScopeTypeRefs, hint: Option, ) -> Result>, ErrorKind> { @@ -206,7 +211,7 @@ impl FunctionDefinitionKind { impl Block { fn infer_types<'s>( &mut self, - state: &mut TypeInferencePassState, + state: &mut TypecheckPassState, outer_refs: &'s ScopeTypeRefs, ) -> Result<(ReturnKind, TypeRef<'s>), ErrorKind> { let mut state = state.inner(); @@ -293,7 +298,7 @@ impl Block { impl Expression { fn infer_types<'s>( &mut self, - state: &mut TypeInferencePassState, + state: &mut TypecheckPassState, type_refs: &'s ScopeTypeRefs<'s>, ) -> Result, ErrorKind> { match &mut self.0 { diff --git a/reid/src/mir/typerefs.rs b/reid/src/mir/typecheck/typerefs.rs similarity index 91% rename from reid/src/mir/typerefs.rs rename to reid/src/mir/typecheck/typerefs.rs index f47e02a..f87a189 100644 --- a/reid/src/mir/typerefs.rs +++ b/reid/src/mir/typecheck/typerefs.rs @@ -4,12 +4,11 @@ use std::{ rc::Rc, }; -use crate::mir::VagueType; +use crate::mir::{BinaryOperator, TypeKind, VagueType}; use super::{ - pass::{ScopeBinopDef, ScopeBinopKey, Storage}, - typecheck::ErrorKind, - BinaryOperator, TypeKind, + super::pass::{ScopeBinopDef, ScopeBinopKey, Storage}, + ErrorKind, }; #[derive(Clone)] @@ -43,7 +42,7 @@ impl<'scope> TypeRef<'scope> { } pub fn as_type(&self) -> TypeKind { - TypeKind::Vague(super::VagueType::TypeRef(*self.0.borrow())) + TypeKind::Vague(VagueType::TypeRef(*self.0.borrow())) } } @@ -66,6 +65,23 @@ pub struct TypeRefs { pub(super) type_refs: RefCell>, } +impl std::fmt::Display for TypeRefs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for (i, typeref) in self.type_refs.borrow().iter().enumerate() { + let idx = *typeref.borrow(); + writeln!( + f, + "{:<3} = {:<3} = {:?} = {}", + i, + unsafe { *self.recurse_type_ref(idx).borrow() }, + self.retrieve_type(idx), + TypeKind::Vague(VagueType::TypeRef(idx)).resolve_ref(self) + )?; + } + Ok(()) + } +} + impl TypeRefs { pub fn new(&self, ty: &TypeKind) -> TypeIdRef { let idx = self.hints.borrow().len(); @@ -157,7 +173,7 @@ impl<'outer> ScopeTypeRefs<'outer> { pub fn from_type(&'outer self, ty: &TypeKind) -> Option> { let idx = match ty { - TypeKind::Vague(super::VagueType::TypeRef(idx)) => { + TypeKind::Vague(VagueType::TypeRef(idx)) => { let inner_idx = unsafe { *self.types.recurse_type_ref(*idx).borrow() }; self.types.type_refs.borrow().get(inner_idx).cloned()? } diff --git a/reid/src/util.rs b/reid/src/util.rs index 61b2cd8..888078f 100644 --- a/reid/src/util.rs +++ b/reid/src/util.rs @@ -19,3 +19,14 @@ pub fn try_all(list: Vec>) -> Result, Vec> { Ok(successes) } } + +pub fn maybe(lhs: Option, rhs: Option, fun: T) -> Option +where + T: FnOnce(U, U) -> U, +{ + if let (Some(lhs), Some(rhs)) = (lhs, rhs) { + Some(fun(lhs, rhs)) + } else { + None + } +}