Refactor typecheck into it's own module
This commit is contained in:
		
							parent
							
								
									0b3ee3bf92
								
							
						
					
					
						commit
						f8d2e4996a
					
				| @ -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<token_stream::Error>), | ||||
|     #[error("{}{}", label("(TypeCheck) "), .0.kind)] | ||||
|     TypeCheckError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>), | ||||
|     TypeCheckError(#[source] mir::pass::Error<typecheck::ErrorKind>), | ||||
|     #[error("{}{}", label("(TypeInference) "), .0.kind)] | ||||
|     TypeInferenceError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>), | ||||
|     TypeInferenceError(#[source] mir::pass::Error<TypecheckError>), | ||||
|     #[error("{}{}", label("(Linker) "), .0.kind)] | ||||
|     LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>), | ||||
|     #[error("{}{}", label("(Codegen) "), .0)] | ||||
| @ -36,11 +38,11 @@ pub enum ErrorKind { | ||||
| } | ||||
| 
 | ||||
| impl ErrorKind { | ||||
|     pub fn from_typecheck(err: mir::pass::Error<mir::typecheck::ErrorKind>) -> ErrorKind { | ||||
|     pub fn from_typecheck(err: mir::pass::Error<typecheck::ErrorKind>) -> ErrorKind { | ||||
|         ErrorKind::TypeCheckError(err) | ||||
|     } | ||||
| 
 | ||||
|     pub fn from_typeinference(err: mir::pass::Error<mir::typecheck::ErrorKind>) -> ErrorKind { | ||||
|     pub fn from_typeinference(err: mir::pass::Error<typecheck::ErrorKind>) -> ErrorKind { | ||||
|         ErrorKind::TypeInferenceError(err) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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}; | ||||
| 
 | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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<Box<Expression>>), | ||||
| } | ||||
| 
 | ||||
| impl TypeKind { | ||||
|     pub fn collapse_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> { | ||||
|         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<TypeKind, ErrorKind> { | ||||
|         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<TypeKind> { | ||||
| @ -365,11 +298,6 @@ impl StructType { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| enum BlockReturn<'b> { | ||||
|     Early(&'b Statement), | ||||
|     Normal(ReturnKind, &'b Option<Box<Expression>>), | ||||
| } | ||||
| 
 | ||||
| impl Block { | ||||
|     fn return_expr(&self) -> Result<BlockReturn, ReturnTypeOther> { | ||||
|         let mut early_return = None; | ||||
| @ -566,15 +494,7 @@ impl Expression { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_zero(&self) -> Result<Option<bool>, ErrorKind> { | ||||
|         if let Some(val) = self.num_value()? { | ||||
|             Ok(Some(val == 0)) | ||||
|         } else { | ||||
|             Ok(None) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn num_value(&self) -> Result<Option<i128>, ErrorKind> { | ||||
|     pub fn num_value(&self) -> Result<Option<i128>, 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<T>(lhs: Option<i128>, rhs: Option<i128>, fun: T) -> Option<i128> | ||||
| 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<T>(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<TypeKind, ErrorKind> { | ||||
|         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<TypeKind, ErrorKind> { | ||||
|         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<i128> { | ||||
|         match self { | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
							
								
								
									
										241
									
								
								reid/src/mir/typecheck/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								reid/src/mir/typecheck/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -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<TypeKind, ErrorKind> { | ||||
|         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<TypeKind, ErrorKind> { | ||||
|         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<TypeKind, ErrorKind> { | ||||
|         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<TypeKind, ErrorKind> { | ||||
|         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<TypeKind, ErrorKind> { | ||||
|         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(()), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -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<TypeKind, ErrorKind> { | ||||
|         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 {} | ||||
| @ -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<TypeKind>, | ||||
|     ) -> Result<Option<TypeRef<'s>>, 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<TypeRef<'s>, ErrorKind> { | ||||
|         match &mut self.0 { | ||||
| @ -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<Vec<TypeIdRef>>, | ||||
| } | ||||
| 
 | ||||
| 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<TypeRef<'outer>> { | ||||
|         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()? | ||||
|             } | ||||
| @ -19,3 +19,14 @@ pub fn try_all<U, E>(list: Vec<Result<U, E>>) -> Result<Vec<U>, Vec<E>> { | ||||
|         Ok(successes) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn maybe<T, U>(lhs: Option<U>, rhs: Option<U>, fun: T) -> Option<U> | ||||
| where | ||||
|     T: FnOnce(U, U) -> U, | ||||
| { | ||||
|     if let (Some(lhs), Some(rhs)) = (lhs, rhs) { | ||||
|         Some(fun(lhs, rhs)) | ||||
|     } else { | ||||
|         None | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user