Refactor typecheck into it's own module

This commit is contained in:
Sofia 2025-07-25 16:15:50 +03:00
parent 0b3ee3bf92
commit f8d2e4996a
10 changed files with 325 additions and 303 deletions

View File

@ -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)
}
}

View File

@ -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};

View File

@ -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 {

View File

@ -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 {

View File

@ -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);

View 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(()),
}
}
}

View File

@ -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 {}

View File

@ -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 {

View File

@ -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()?
}

View File

@ -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
}
}