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