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}, |     ast::token_stream::{self, TokenRange}, | ||||||
|     codegen, |     codegen, | ||||||
|     lexer::{self, Cursor, FullToken, Position}, |     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 { | fn label(text: &str) -> &str { | ||||||
|     #[cfg(debug_assertions)] |     #[cfg(debug_assertions)] | ||||||
|     { |     { | ||||||
| @ -26,9 +28,9 @@ pub enum ErrorKind { | |||||||
|     #[error("{}{}", label("(Parsing) "), .0.kind)] |     #[error("{}{}", label("(Parsing) "), .0.kind)] | ||||||
|     ParserError(#[from] mir::pass::Error<token_stream::Error>), |     ParserError(#[from] mir::pass::Error<token_stream::Error>), | ||||||
|     #[error("{}{}", label("(TypeCheck) "), .0.kind)] |     #[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)] |     #[error("{}{}", label("(TypeInference) "), .0.kind)] | ||||||
|     TypeInferenceError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>), |     TypeInferenceError(#[source] mir::pass::Error<TypecheckError>), | ||||||
|     #[error("{}{}", label("(Linker) "), .0.kind)] |     #[error("{}{}", label("(Linker) "), .0.kind)] | ||||||
|     LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>), |     LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>), | ||||||
|     #[error("{}{}", label("(Codegen) "), .0)] |     #[error("{}{}", label("(Codegen) "), .0)] | ||||||
| @ -36,11 +38,11 @@ pub enum ErrorKind { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl 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) |         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) |         ErrorKind::TypeInferenceError(err) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -50,7 +50,8 @@ use ast::{ | |||||||
| use codegen::intrinsics::{form_intrinsic_binops, form_intrinsics}; | use codegen::intrinsics::{form_intrinsic_binops, form_intrinsics}; | ||||||
| use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError}; | use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError}; | ||||||
| use mir::{ | 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}; | use reid_lib::{compile::CompileOutput, Context}; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,24 +2,7 @@ use std::fmt::{Debug, Display, Write}; | |||||||
| 
 | 
 | ||||||
| use crate::pad_adapter::PadAdapter; | use crate::pad_adapter::PadAdapter; | ||||||
| 
 | 
 | ||||||
| use super::{typerefs::TypeRefs, *}; | use super::{typecheck::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(()) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| impl Display for Context { | impl Display for Context { | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |     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)] | #[derive(Debug, Clone)] | ||||||
| pub enum ReturnTypeOther { | pub enum ReturnTypeOther { | ||||||
| @ -12,87 +14,18 @@ pub enum ReturnTypeOther { | |||||||
|     Loop, |     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 { | 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
 |     /// Return the type that is the result of a binary operator between two
 | ||||||
|     /// values of this type
 |     /// values of this type
 | ||||||
|     pub fn simple_binop_type(&self, op: &BinaryOperator) -> Option<TypeKind> { |     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 { | impl Block { | ||||||
|     fn return_expr(&self) -> Result<BlockReturn, ReturnTypeOther> { |     fn return_expr(&self) -> Result<BlockReturn, ReturnTypeOther> { | ||||||
|         let mut early_return = None; |         let mut early_return = None; | ||||||
| @ -566,15 +494,7 @@ impl Expression { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn is_zero(&self) -> Result<Option<bool>, ErrorKind> { |     pub fn num_value(&self) -> Result<Option<i128>, NumValueError> { | ||||||
|         if let Some(val) = self.num_value()? { |  | ||||||
|             Ok(Some(val == 0)) |  | ||||||
|         } else { |  | ||||||
|             Ok(None) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn num_value(&self) -> Result<Option<i128>, ErrorKind> { |  | ||||||
|         Ok(match &self.0 { |         Ok(match &self.0 { | ||||||
|             ExprKind::Variable(_) => None, |             ExprKind::Variable(_) => None, | ||||||
|             ExprKind::Indexed(..) => None, |             ExprKind::Indexed(..) => None, | ||||||
| @ -591,14 +511,14 @@ impl Expression { | |||||||
|                 BinaryOperator::Div => { |                 BinaryOperator::Div => { | ||||||
|                     let rhs_value = rhs.num_value()?; |                     let rhs_value = rhs.num_value()?; | ||||||
|                     if rhs_value == Some(0) { |                     if rhs_value == Some(0) { | ||||||
|                         Err(ErrorKind::DivideZero)? |                         Err(NumValueError::DivideZero)? | ||||||
|                     } |                     } | ||||||
|                     maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a / b) |                     maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a / b) | ||||||
|                 } |                 } | ||||||
|                 BinaryOperator::Mod => { |                 BinaryOperator::Mod => { | ||||||
|                     let rhs_value = rhs.num_value()?; |                     let rhs_value = rhs.num_value()?; | ||||||
|                     if rhs_value == Some(0) { |                     if rhs_value == Some(0) { | ||||||
|                         Err(ErrorKind::DivideZero)? |                         Err(NumValueError::DivideZero)? | ||||||
|                     } |                     } | ||||||
|                     maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a % b) |                     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 { | impl IfExpression { | ||||||
|     pub fn return_type( |     pub fn return_type( | ||||||
|         &self, |         &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 { | impl Literal { | ||||||
|     pub fn num_value(&self) -> Option<i128> { |     pub fn num_value(&self) -> Option<i128> { | ||||||
|         match self { |         match self { | ||||||
|  | |||||||
| @ -15,8 +15,6 @@ pub mod implement; | |||||||
| pub mod linker; | pub mod linker; | ||||||
| pub mod pass; | pub mod pass; | ||||||
| pub mod typecheck; | pub mod typecheck; | ||||||
| pub mod typeinference; |  | ||||||
| pub mod typerefs; |  | ||||||
| 
 | 
 | ||||||
| #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] | ||||||
| pub struct SourceModuleId(pub u32); | 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 VagueType as Vague; | ||||||
| 
 | 
 | ||||||
| use super::{ | use super::{ | ||||||
|     pass::{Pass, PassResult, PassState, ScopeVariable}, |     super::pass::{Pass, PassResult, ScopeVariable}, | ||||||
|     typerefs::TypeRefs, |     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
 | /// Struct used to implement a type-checking pass that can be performed on the
 | ||||||
| /// MIR.
 | /// MIR.
 | ||||||
| pub struct TypeCheck<'t> { | pub struct TypeCheck<'t> { | ||||||
|     pub refs: &'t TypeRefs, |     pub refs: &'t TypeRefs, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type TypecheckPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>; |  | ||||||
| 
 |  | ||||||
| #[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | #[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | ||||||
| pub enum ErrorTypedefKind { | pub enum ErrorTypedefKind { | ||||||
|     #[error("locally")] |     #[error("locally")] | ||||||
| @ -920,32 +853,4 @@ impl Literal { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl TypeKind { | 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(()), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -10,17 +10,24 @@ use std::{ | |||||||
|     iter, |     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::{ | use super::{ | ||||||
|     pass::{Pass, PassResult, PassState, ScopeBinopKey}, |     super::{ | ||||||
|     typecheck::{ErrorKind, ErrorTypedefKind}, |         pass::{Pass, PassResult, PassState, ScopeBinopKey}, | ||||||
|  |         TypeKind::*, | ||||||
|  |         VagueType::*, | ||||||
|  |     }, | ||||||
|  |     typecheck::ErrorTypedefKind, | ||||||
|     typerefs::{ScopeTypeRefs, TypeRef, TypeRefs}, |     typerefs::{ScopeTypeRefs, TypeRef, TypeRefs}, | ||||||
|     BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, |     ErrorKind, TypecheckPassState, | ||||||
|     FunctionDefinitionKind, IfExpression, Module, ReturnKind, StmtKind, |  | ||||||
|     TypeKind::*, |  | ||||||
|     VagueType::*, |  | ||||||
|     WhileStatement, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Struct used to implement Type Inference, where an intermediary
 | /// Struct used to implement Type Inference, where an intermediary
 | ||||||
| @ -30,13 +37,11 @@ pub struct TypeInference<'t> { | |||||||
|     pub refs: &'t TypeRefs, |     pub refs: &'t TypeRefs, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type TypeInferencePassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>; |  | ||||||
| 
 |  | ||||||
| impl<'t> Pass for TypeInference<'t> { | impl<'t> Pass for TypeInference<'t> { | ||||||
|     type Data = (); |     type Data = (); | ||||||
|     type TError = ErrorKind; |     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(); |         let mut seen_functions = HashMap::new(); | ||||||
|         for function in &mut module.functions { |         for function in &mut module.functions { | ||||||
|             if let Some(kind) = seen_functions.get(&function.name) { |             if let Some(kind) = seen_functions.get(&function.name) { | ||||||
| @ -98,7 +103,7 @@ impl BinopDefinition { | |||||||
|     fn infer_types( |     fn infer_types( | ||||||
|         &mut self, |         &mut self, | ||||||
|         type_refs: &TypeRefs, |         type_refs: &TypeRefs, | ||||||
|         state: &mut TypeInferencePassState, |         state: &mut TypecheckPassState, | ||||||
|     ) -> Result<(), ErrorKind> { |     ) -> Result<(), ErrorKind> { | ||||||
|         let scope_hints = ScopeTypeRefs::from(type_refs); |         let scope_hints = ScopeTypeRefs::from(type_refs); | ||||||
| 
 | 
 | ||||||
| @ -142,7 +147,7 @@ impl FunctionDefinition { | |||||||
|     fn infer_types( |     fn infer_types( | ||||||
|         &mut self, |         &mut self, | ||||||
|         type_refs: &TypeRefs, |         type_refs: &TypeRefs, | ||||||
|         state: &mut TypeInferencePassState, |         state: &mut TypecheckPassState, | ||||||
|     ) -> Result<(), ErrorKind> { |     ) -> Result<(), ErrorKind> { | ||||||
|         let scope_refs = ScopeTypeRefs::from(type_refs); |         let scope_refs = ScopeTypeRefs::from(type_refs); | ||||||
|         for param in &self.parameters { |         for param in &self.parameters { | ||||||
| @ -183,7 +188,7 @@ impl FunctionDefinition { | |||||||
| impl FunctionDefinitionKind { | impl FunctionDefinitionKind { | ||||||
|     fn infer_types<'s>( |     fn infer_types<'s>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         state: &mut TypeInferencePassState, |         state: &mut TypecheckPassState, | ||||||
|         scope_refs: &'s ScopeTypeRefs, |         scope_refs: &'s ScopeTypeRefs, | ||||||
|         hint: Option<TypeKind>, |         hint: Option<TypeKind>, | ||||||
|     ) -> Result<Option<TypeRef<'s>>, ErrorKind> { |     ) -> Result<Option<TypeRef<'s>>, ErrorKind> { | ||||||
| @ -206,7 +211,7 @@ impl FunctionDefinitionKind { | |||||||
| impl Block { | impl Block { | ||||||
|     fn infer_types<'s>( |     fn infer_types<'s>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         state: &mut TypeInferencePassState, |         state: &mut TypecheckPassState, | ||||||
|         outer_refs: &'s ScopeTypeRefs, |         outer_refs: &'s ScopeTypeRefs, | ||||||
|     ) -> Result<(ReturnKind, TypeRef<'s>), ErrorKind> { |     ) -> Result<(ReturnKind, TypeRef<'s>), ErrorKind> { | ||||||
|         let mut state = state.inner(); |         let mut state = state.inner(); | ||||||
| @ -293,7 +298,7 @@ impl Block { | |||||||
| impl Expression { | impl Expression { | ||||||
|     fn infer_types<'s>( |     fn infer_types<'s>( | ||||||
|         &mut self, |         &mut self, | ||||||
|         state: &mut TypeInferencePassState, |         state: &mut TypecheckPassState, | ||||||
|         type_refs: &'s ScopeTypeRefs<'s>, |         type_refs: &'s ScopeTypeRefs<'s>, | ||||||
|     ) -> Result<TypeRef<'s>, ErrorKind> { |     ) -> Result<TypeRef<'s>, ErrorKind> { | ||||||
|         match &mut self.0 { |         match &mut self.0 { | ||||||
| @ -4,12 +4,11 @@ use std::{ | |||||||
|     rc::Rc, |     rc::Rc, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| use crate::mir::VagueType; | use crate::mir::{BinaryOperator, TypeKind, VagueType}; | ||||||
| 
 | 
 | ||||||
| use super::{ | use super::{ | ||||||
|     pass::{ScopeBinopDef, ScopeBinopKey, Storage}, |     super::pass::{ScopeBinopDef, ScopeBinopKey, Storage}, | ||||||
|     typecheck::ErrorKind, |     ErrorKind, | ||||||
|     BinaryOperator, TypeKind, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| @ -43,7 +42,7 @@ impl<'scope> TypeRef<'scope> { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn as_type(&self) -> TypeKind { |     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>>, |     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 { | impl TypeRefs { | ||||||
|     pub fn new(&self, ty: &TypeKind) -> TypeIdRef { |     pub fn new(&self, ty: &TypeKind) -> TypeIdRef { | ||||||
|         let idx = self.hints.borrow().len(); |         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>> { |     pub fn from_type(&'outer self, ty: &TypeKind) -> Option<TypeRef<'outer>> { | ||||||
|         let idx = match ty { |         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() }; |                 let inner_idx = unsafe { *self.types.recurse_type_ref(*idx).borrow() }; | ||||||
|                 self.types.type_refs.borrow().get(inner_idx).cloned()? |                 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) |         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