Type-infer and check typecasting
This commit is contained in:
		
							parent
							
								
									3378f556ec
								
							
						
					
					
						commit
						104205ee5d
					
				| @ -14,6 +14,82 @@ pub enum ReturnTypeOther { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 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()), | ||||||
|  |                 _ => match (&self_cat, &other_cat) { | ||||||
|  |                     (TypeCategory::Integer, TypeCategory::Integer) => Ok(other.clone()), | ||||||
|  |                     (TypeCategory::Real, TypeCategory::Real) => Ok(other.clone()), | ||||||
|  |                     _ => Err(ErrorKind::NotCastableTo(self.clone(), other.clone())), | ||||||
|  |                 }, | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /// Return the type that is the result of a binary operator between two
 |     /// Return the type that is the result of a binary operator between two
 | ||||||
|     /// values of this type
 |     /// values of this type
 | ||||||
|     pub fn binop_type(&self, op: &BinaryOperator) -> TypeKind { |     pub fn binop_type(&self, op: &BinaryOperator) -> TypeKind { | ||||||
| @ -159,6 +235,49 @@ impl TypeKind { | |||||||
|             _ => true, |             _ => true, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     pub fn category(&self) -> TypeCategory { | ||||||
|  |         match self { | ||||||
|  |             TypeKind::I8 | ||||||
|  |             | TypeKind::I16 | ||||||
|  |             | TypeKind::I32 | ||||||
|  |             | TypeKind::I64 | ||||||
|  |             | TypeKind::I128 | ||||||
|  |             | TypeKind::U8 | ||||||
|  |             | TypeKind::U16 | ||||||
|  |             | TypeKind::U32 | ||||||
|  |             | TypeKind::U64 | ||||||
|  |             | TypeKind::U128 | ||||||
|  |             | TypeKind::Str => TypeCategory::Integer, | ||||||
|  |             TypeKind::F16 | ||||||
|  |             | TypeKind::F32B | ||||||
|  |             | TypeKind::F32 | ||||||
|  |             | TypeKind::F64 | ||||||
|  |             | TypeKind::F128 | ||||||
|  |             | TypeKind::F80 | ||||||
|  |             | TypeKind::F128PPC => TypeCategory::Real, | ||||||
|  |             TypeKind::Void => TypeCategory::Other, | ||||||
|  |             TypeKind::Bool => TypeCategory::Other, | ||||||
|  |             TypeKind::Array(_, _) => TypeCategory::Other, | ||||||
|  |             TypeKind::CustomType(_) => TypeCategory::Other, | ||||||
|  |             TypeKind::Borrow(_, _) => TypeCategory::Other, | ||||||
|  |             TypeKind::UserPtr(_) => TypeCategory::Other, | ||||||
|  |             TypeKind::CodegenPtr(_) => TypeCategory::Other, | ||||||
|  |             TypeKind::Vague(vague_type) => match vague_type { | ||||||
|  |                 VagueType::Unknown => TypeCategory::Other, | ||||||
|  |                 VagueType::Integer => TypeCategory::Integer, | ||||||
|  |                 VagueType::Decimal => TypeCategory::Real, | ||||||
|  |                 VagueType::TypeRef(_) => TypeCategory::TypeRef, | ||||||
|  |             }, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub enum TypeCategory { | ||||||
|  |     Integer, | ||||||
|  |     Real, | ||||||
|  |     Other, | ||||||
|  |     TypeRef, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl StructType { | impl StructType { | ||||||
| @ -467,73 +586,6 @@ impl TypeKind { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub trait Collapsable: Sized + Clone { |  | ||||||
|     /// Try to narrow two types into one singular type. E.g. Vague(Number) and
 |  | ||||||
|     /// I32 could be narrowed to just I32.
 |  | ||||||
|     fn collapse_into(&self, other: &Self) -> Result<Self, ErrorKind>; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Collapsable for TypeKind { |  | ||||||
|     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())), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Literal { | impl Literal { | ||||||
|     pub fn num_value(&self) -> Option<i128> { |     pub fn num_value(&self) -> Option<i128> { | ||||||
|         match self { |         match self { | ||||||
| @ -562,22 +614,6 @@ impl Literal { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Collapsable for ScopeFunction { |  | ||||||
|     fn collapse_into(&self, other: &ScopeFunction) -> Result<ScopeFunction, ErrorKind> { |  | ||||||
|         Ok(ScopeFunction { |  | ||||||
|             ret: self.ret.collapse_into(&other.ret)?, |  | ||||||
|             params: try_all( |  | ||||||
|                 self.params |  | ||||||
|                     .iter() |  | ||||||
|                     .zip(&other.params) |  | ||||||
|                     .map(|(p1, p2)| p1.collapse_into(&p2)) |  | ||||||
|                     .collect(), |  | ||||||
|             ) |  | ||||||
|             .map_err(|e| e.first().unwrap().clone())?, |  | ||||||
|         }) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone, thiserror::Error, PartialEq, Eq, PartialOrd, Ord)] | #[derive(Debug, Clone, thiserror::Error, PartialEq, Eq, PartialOrd, Ord)] | ||||||
| pub enum EqualsIssue { | pub enum EqualsIssue { | ||||||
|     #[error("Function is already defined locally at {:?}", (.0).range)] |     #[error("Function is already defined locally at {:?}", (.0).range)] | ||||||
|  | |||||||
| @ -72,7 +72,7 @@ impl<'map> Pass for LinkerPass<'map> { | |||||||
|     type Data = (); |     type Data = (); | ||||||
|     type TError = ErrorKind; |     type TError = ErrorKind; | ||||||
|     fn context(&mut self, context: &mut Context, mut state: LinkerPassState) -> PassResult { |     fn context(&mut self, context: &mut Context, mut state: LinkerPassState) -> PassResult { | ||||||
|         let mut mains = context |         let mains = context | ||||||
|             .modules |             .modules | ||||||
|             .iter_mut() |             .iter_mut() | ||||||
|             .filter(|m| m.is_main) |             .filter(|m| m.is_main) | ||||||
|  | |||||||
| @ -6,7 +6,6 @@ use crate::{mir::*, util::try_all}; | |||||||
| use VagueType as Vague; | use VagueType as Vague; | ||||||
| 
 | 
 | ||||||
| use super::{ | use super::{ | ||||||
|     implement::Collapsable, |  | ||||||
|     pass::{Pass, PassResult, PassState, ScopeVariable}, |     pass::{Pass, PassResult, PassState, ScopeVariable}, | ||||||
|     typerefs::TypeRefs, |     typerefs::TypeRefs, | ||||||
| }; | }; | ||||||
| @ -67,6 +66,8 @@ pub enum ErrorKind { | |||||||
|     ImpossibleMutLet(String), |     ImpossibleMutLet(String), | ||||||
|     #[error("Cannot produce a negative unsigned value of type {0}!")] |     #[error("Cannot produce a negative unsigned value of type {0}!")] | ||||||
|     NegativeUnsignedValue(TypeKind), |     NegativeUnsignedValue(TypeKind), | ||||||
|  |     #[error("Cannot cast type {0} into type {1}!")] | ||||||
|  |     NotCastableTo(TypeKind, TypeKind), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Struct used to implement a type-checking pass that can be performed on the
 | /// Struct used to implement a type-checking pass that can be performed on the
 | ||||||
| @ -712,7 +713,10 @@ impl Expression { | |||||||
| 
 | 
 | ||||||
|                 Ok(*inner) |                 Ok(*inner) | ||||||
|             } |             } | ||||||
|             ExprKind::CastTo(expression, type_kind) => todo!(), |             ExprKind::CastTo(expression, type_kind) => { | ||||||
|  |                 let expr = expression.typecheck(state, typerefs, None)?; | ||||||
|  |                 expr.resolve_ref(typerefs).cast_into(type_kind) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -397,7 +397,10 @@ impl Expression { | |||||||
|                     _ => Err(ErrorKind::AttemptedDerefNonBorrow(var.1.clone())), |                     _ => Err(ErrorKind::AttemptedDerefNonBorrow(var.1.clone())), | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             ExprKind::CastTo(expression, type_kind) => todo!(), |             ExprKind::CastTo(expression, type_kind) => { | ||||||
|  |                 expression.infer_types(state, type_refs)?; | ||||||
|  |                 Ok(type_refs.from_type(type_kind).unwrap()) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ use std::{ | |||||||
| 
 | 
 | ||||||
| use crate::mir::VagueType; | use crate::mir::VagueType; | ||||||
| 
 | 
 | ||||||
| use super::{implement::Collapsable, typecheck::ErrorKind, BinaryOperator, TypeKind}; | use super::{typecheck::ErrorKind, BinaryOperator, TypeKind}; | ||||||
| 
 | 
 | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| pub struct TypeRef<'scope>(TypeIdRef, &'scope ScopeTypeRefs<'scope>); | pub struct TypeRef<'scope>(TypeIdRef, &'scope ScopeTypeRefs<'scope>); | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								reid_src/cast.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								reid_src/cast.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | // Arithmetic, function calls and imports! | ||||||
|  | 
 | ||||||
|  | fn other() -> u16 { | ||||||
|  |   return 6; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> u32 { | ||||||
|  |   let value = other() as u32; | ||||||
|  | 
 | ||||||
|  |   return value; | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user