Compare commits
No commits in common. "77439ee34ac38946b133dab2450b6962555a797f" and "b012a46e9101080a54002cb4f6e84693ba819a60" have entirely different histories.
77439ee34a
...
b012a46e91
@ -2,7 +2,7 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self},
|
ast::{self},
|
||||||
mir::{self, NamedVariableRef, StmtKind, StructType},
|
mir::{self, NamedVariableRef, StmtKind},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl mir::Context {
|
impl mir::Context {
|
||||||
@ -68,12 +68,12 @@ impl ast::Module {
|
|||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
kind: match kind {
|
kind: match kind {
|
||||||
ast::TypeDefinitionKind::Struct(struct_definition_fields) => {
|
ast::TypeDefinitionKind::Struct(struct_definition_fields) => {
|
||||||
mir::TypeDefinitionKind::Struct(StructType(
|
mir::TypeDefinitionKind::Struct(
|
||||||
struct_definition_fields
|
struct_definition_fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| (s.name.clone(), s.ty.clone().into()))
|
.map(|s| (s.name.clone(), s.ty.clone().into()))
|
||||||
.collect(),
|
.collect(),
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
meta: (*range).into(),
|
meta: (*range).into(),
|
||||||
|
@ -518,7 +518,7 @@ impl TypeKind {
|
|||||||
TypeKind::Array(elem_t, _) => Type::Ptr(Box::new(elem_t.get_type())),
|
TypeKind::Array(elem_t, _) => Type::Ptr(Box::new(elem_t.get_type())),
|
||||||
TypeKind::Void => Type::Void,
|
TypeKind::Void => Type::Void,
|
||||||
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
|
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
|
||||||
TypeKind::CustomType(_) => todo!("codegen for custom type"),
|
TypeKind::CustomType(_, custom_type_kind) => todo!("codegen for custom type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,12 +124,10 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> {
|
|||||||
|
|
||||||
let state = context.pass(&mut TypeInference { refs: &refs });
|
let state = context.pass(&mut TypeInference { refs: &refs });
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
dbg!(&refs);
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("{}", &context);
|
println!("{}", &context);
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
dbg!(&state);
|
dbg!(&state, &refs);
|
||||||
|
|
||||||
if !state.errors.is_empty() {
|
if !state.errors.is_empty() {
|
||||||
return Err(ReidError::TypeInferenceErrors(state.errors));
|
return Err(ReidError::TypeInferenceErrors(state.errors));
|
||||||
|
@ -55,7 +55,7 @@ impl Display for TypeDefinitionKind {
|
|||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
let mut state = Default::default();
|
let mut state = Default::default();
|
||||||
let mut inner_f = PadAdapter::wrap(f, &mut state);
|
let mut inner_f = PadAdapter::wrap(f, &mut state);
|
||||||
for (field_name, field_ty) in &items.0 {
|
for (field_name, field_ty) in items {
|
||||||
writeln!(inner_f, "{}: {:?},", field_name, field_ty)?;
|
writeln!(inner_f, "{}: {:?},", field_name, field_ty)?;
|
||||||
}
|
}
|
||||||
f.write_char('}')
|
f.write_char('}')
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
//! Reid. It contains a simplified version of Reid which can be e.g.
|
//! Reid. It contains a simplified version of Reid which can be e.g.
|
||||||
//! typechecked.
|
//! typechecked.
|
||||||
|
|
||||||
use std::{collections::HashMap, path::PathBuf};
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::token_stream::TokenRange;
|
use crate::{ast::Type, token_stream::TokenRange};
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
pub mod linker;
|
pub mod linker;
|
||||||
@ -65,8 +65,8 @@ pub enum TypeKind {
|
|||||||
StringPtr,
|
StringPtr,
|
||||||
#[error("[{0}; {1}]")]
|
#[error("[{0}; {1}]")]
|
||||||
Array(Box<TypeKind>, u64),
|
Array(Box<TypeKind>, u64),
|
||||||
#[error("{0}")]
|
#[error("{0} ({1})")]
|
||||||
CustomType(String),
|
CustomType(String, CustomTypeKind),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Vague(#[from] VagueType),
|
Vague(#[from] VagueType),
|
||||||
}
|
}
|
||||||
@ -81,10 +81,13 @@ pub enum VagueType {
|
|||||||
TypeRef(usize),
|
TypeRef(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
|
||||||
pub struct StructType(pub Vec<(String, TypeKind)>);
|
pub enum CustomTypeKind {
|
||||||
|
#[error("struct({0:?})")]
|
||||||
pub type TypedefMap = HashMap<String, TypeDefinitionKind>;
|
Struct(Vec<TypeKind>),
|
||||||
|
#[error("CustomType")]
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
impl TypeKind {
|
impl TypeKind {
|
||||||
pub fn known(&self) -> Result<TypeKind, VagueType> {
|
pub fn known(&self) -> Result<TypeKind, VagueType> {
|
||||||
@ -97,7 +100,7 @@ impl TypeKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TypeKind {
|
impl TypeKind {
|
||||||
pub fn signed(&self, typedefs: &TypedefMap) -> bool {
|
pub fn signed(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
TypeKind::Void => false,
|
TypeKind::Void => false,
|
||||||
TypeKind::Vague(_) => false,
|
TypeKind::Vague(_) => false,
|
||||||
@ -114,13 +117,11 @@ impl TypeKind {
|
|||||||
TypeKind::U128 => false,
|
TypeKind::U128 => false,
|
||||||
TypeKind::StringPtr => false,
|
TypeKind::StringPtr => false,
|
||||||
TypeKind::Array(_, _) => false,
|
TypeKind::Array(_, _) => false,
|
||||||
TypeKind::CustomType(name) => match typedefs.get(name).unwrap() {
|
TypeKind::CustomType(_, _) => false,
|
||||||
TypeDefinitionKind::Struct(_) => false,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_maths(&self, typedefs: &TypedefMap) -> bool {
|
pub fn is_maths(&self) -> bool {
|
||||||
use TypeKind::*;
|
use TypeKind::*;
|
||||||
match &self {
|
match &self {
|
||||||
I8 => true,
|
I8 => true,
|
||||||
@ -138,9 +139,7 @@ impl TypeKind {
|
|||||||
Void => false,
|
Void => false,
|
||||||
StringPtr => false,
|
StringPtr => false,
|
||||||
Array(_, _) => false,
|
Array(_, _) => false,
|
||||||
TypeKind::CustomType(name) => match typedefs.get(name).unwrap() {
|
TypeKind::CustomType(_, _) => false,
|
||||||
TypeDefinitionKind::Struct(_) => false,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,9 +328,9 @@ pub struct TypeDefinition {
|
|||||||
pub meta: Metadata,
|
pub meta: Metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub enum TypeDefinitionKind {
|
pub enum TypeDefinitionKind {
|
||||||
Struct(StructType),
|
Struct(Vec<(String, Type)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -109,7 +109,6 @@ impl<T: Clone + std::fmt::Debug> Storage<T> {
|
|||||||
pub struct Scope {
|
pub struct Scope {
|
||||||
pub function_returns: Storage<ScopeFunction>,
|
pub function_returns: Storage<ScopeFunction>,
|
||||||
pub variables: Storage<ScopeVariable>,
|
pub variables: Storage<ScopeVariable>,
|
||||||
pub types: Storage<TypeDefinitionKind>,
|
|
||||||
/// Hard Return type of this scope, if inside a function
|
/// Hard Return type of this scope, if inside a function
|
||||||
pub return_type_hint: Option<TypeKind>,
|
pub return_type_hint: Option<TypeKind>,
|
||||||
}
|
}
|
||||||
@ -131,14 +130,9 @@ impl Scope {
|
|||||||
Scope {
|
Scope {
|
||||||
function_returns: self.function_returns.clone(),
|
function_returns: self.function_returns.clone(),
|
||||||
variables: self.variables.clone(),
|
variables: self.variables.clone(),
|
||||||
types: self.types.clone(),
|
|
||||||
return_type_hint: self.return_type_hint.clone(),
|
return_type_hint: self.return_type_hint.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_typedefs(&self) -> &TypedefMap {
|
|
||||||
&self.types.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PassState<'st, 'sc, TError: STDError + Clone> {
|
pub struct PassState<'st, 'sc, TError: STDError + Clone> {
|
||||||
@ -224,13 +218,6 @@ impl Context {
|
|||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) {
|
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) {
|
||||||
for typedef in &self.typedefs {
|
|
||||||
let kind = match &typedef.kind {
|
|
||||||
TypeDefinitionKind::Struct(fields) => TypeDefinitionKind::Struct(fields.clone()),
|
|
||||||
};
|
|
||||||
scope.types.set(typedef.name.clone(), kind).ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
for function in &self.functions {
|
for function in &self.functions {
|
||||||
scope
|
scope
|
||||||
.function_returns
|
.function_returns
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! This module contains code relevant to doing a type checking pass on the MIR.
|
//! This module contains code relevant to doing a type checking pass on the MIR.
|
||||||
//! During typechecking relevant types are also coerced if possible.
|
//! During typechecking relevant types are also coerced if possible.
|
||||||
use std::{collections::HashSet, convert::Infallible, iter};
|
use std::{convert::Infallible, iter};
|
||||||
|
|
||||||
use crate::{mir::*, util::try_all};
|
use crate::{mir::*, util::try_all};
|
||||||
use VagueType as Vague;
|
use VagueType as Vague;
|
||||||
@ -43,18 +43,6 @@ pub enum ErrorKind {
|
|||||||
TriedIndexingNonArray(TypeKind),
|
TriedIndexingNonArray(TypeKind),
|
||||||
#[error("Index {0} out of bounds ({1})")]
|
#[error("Index {0} out of bounds ({1})")]
|
||||||
IndexOutOfBounds(u64, u64),
|
IndexOutOfBounds(u64, u64),
|
||||||
#[error("No such type {0} could be found")]
|
|
||||||
NoSuchType(String),
|
|
||||||
#[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),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
@ -63,72 +51,10 @@ pub struct TypeCheck<'t> {
|
|||||||
pub refs: &'t TypeRefs,
|
pub refs: &'t TypeRefs,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_typedefs_for_recursion<'a, 'b>(
|
|
||||||
defmap: &'b HashMap<&'a String, &'b TypeDefinition>,
|
|
||||||
typedef: &'b TypeDefinition,
|
|
||||||
mut seen: HashSet<String>,
|
|
||||||
state: &mut PassState<ErrorKind>,
|
|
||||||
) {
|
|
||||||
match &typedef.kind {
|
|
||||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
|
||||||
for field_ty in fields.iter().map(|(_, ty)| ty) {
|
|
||||||
if let TypeKind::CustomType(name) = field_ty {
|
|
||||||
if seen.contains(name) {
|
|
||||||
state.ok::<_, Infallible>(
|
|
||||||
Err(ErrorKind::RecursiveTypeDefinition(
|
|
||||||
typedef.name.clone(),
|
|
||||||
name.clone(),
|
|
||||||
)),
|
|
||||||
typedef.meta,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
seen.insert(name.clone());
|
|
||||||
if let Some(inner_typedef) = defmap.get(name) {
|
|
||||||
check_typedefs_for_recursion(defmap, inner_typedef, seen.clone(), state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'t> Pass for TypeCheck<'t> {
|
impl<'t> Pass for TypeCheck<'t> {
|
||||||
type TError = ErrorKind;
|
type TError = ErrorKind;
|
||||||
|
|
||||||
fn module(&mut self, module: &mut Module, mut state: PassState<ErrorKind>) {
|
fn module(&mut self, module: &mut Module, mut state: PassState<ErrorKind>) {
|
||||||
let mut defmap = HashMap::new();
|
|
||||||
for typedef in &module.typedefs {
|
|
||||||
let TypeDefinition { name, kind, meta } = &typedef;
|
|
||||||
match kind {
|
|
||||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
|
||||||
let mut fieldmap = HashMap::new();
|
|
||||||
for (name, field_ty) in fields {
|
|
||||||
if let Some(_) = fieldmap.insert(name, field_ty) {
|
|
||||||
state.ok::<_, Infallible>(
|
|
||||||
Err(ErrorKind::DuplicateStructField(name.clone())),
|
|
||||||
meta.clone(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(_) = defmap.insert(&typedef.name, typedef) {
|
|
||||||
state.ok::<_, Infallible>(
|
|
||||||
Err(ErrorKind::DuplicateTypeName(name.clone())),
|
|
||||||
meta.clone(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let seen = HashSet::new();
|
|
||||||
for typedef in defmap.values() {
|
|
||||||
let mut curr = seen.clone();
|
|
||||||
curr.insert(typedef.name.clone());
|
|
||||||
check_typedefs_for_recursion(&defmap, typedef, HashSet::new(), &mut state);
|
|
||||||
}
|
|
||||||
|
|
||||||
for function in &mut module.functions {
|
for function in &mut module.functions {
|
||||||
let res = function.typecheck(&self.refs, &mut state.inner());
|
let res = function.typecheck(&self.refs, &mut state.inner());
|
||||||
state.ok(res, function.block_meta());
|
state.ok(res, function.block_meta());
|
||||||
@ -253,8 +179,7 @@ impl Block {
|
|||||||
StmtKind::Set(variable_reference, expression) => {
|
StmtKind::Set(variable_reference, expression) => {
|
||||||
if let Some(var) = state
|
if let Some(var) = state
|
||||||
.ok(
|
.ok(
|
||||||
variable_reference
|
variable_reference.get_variable(&state.scope.variables),
|
||||||
.get_variable(&state.scope.variables, &state.scope.types),
|
|
||||||
variable_reference.meta,
|
variable_reference.meta,
|
||||||
)
|
)
|
||||||
.flatten()
|
.flatten()
|
||||||
@ -562,59 +487,10 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::StructIndex(expression, type_kind, field_name) => {
|
ExprKind::StructIndex(expression, type_kind, _) => {
|
||||||
// Resolve expected type
|
todo!("typechecking for struct index")
|
||||||
let expected_ty = type_kind.resolve_hinted(hints);
|
|
||||||
|
|
||||||
// Typecheck expression
|
|
||||||
let expr_res = expression.typecheck(state, hints, Some(&expected_ty));
|
|
||||||
let expr_ty =
|
|
||||||
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), expression.1);
|
|
||||||
|
|
||||||
if let TypeKind::CustomType(struct_name) = expr_ty {
|
|
||||||
let struct_type = state.scope.get_struct_type(&struct_name)?;
|
|
||||||
if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) {
|
|
||||||
// Make sure they are the same
|
|
||||||
let true_ty = state.or_else(
|
|
||||||
expr_field_ty.collapse_into(&expected_ty),
|
|
||||||
TypeKind::Vague(Vague::Unknown),
|
|
||||||
self.1,
|
|
||||||
);
|
|
||||||
*type_kind = true_ty.clone();
|
|
||||||
// Update possibly resolved type
|
|
||||||
Ok(true_ty)
|
|
||||||
} else {
|
|
||||||
Err(ErrorKind::NoSuchField(field_name.clone()))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(ErrorKind::TriedAccessingNonStruct(expr_ty))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::Struct(struct_name, items) => {
|
|
||||||
let struct_def = state.scope.get_struct_type(struct_name)?.clone();
|
|
||||||
for (field_name, field_expr) in items {
|
|
||||||
// Get expected type, or error if field does not exist
|
|
||||||
let expected_ty = state.or_else(
|
|
||||||
struct_def
|
|
||||||
.get_field_ty(field_name)
|
|
||||||
.ok_or(ErrorKind::NoSuchField(format!(
|
|
||||||
"{}.{}",
|
|
||||||
struct_name, field_name
|
|
||||||
))),
|
|
||||||
&TypeKind::Vague(VagueType::Unknown),
|
|
||||||
field_expr.1,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Typecheck the actual expression
|
|
||||||
let expr_res = field_expr.typecheck(state, hints, Some(expected_ty));
|
|
||||||
let expr_ty =
|
|
||||||
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), field_expr.1);
|
|
||||||
|
|
||||||
// Make sure both are the same type, report error if not
|
|
||||||
state.ok(expr_ty.collapse_into(&expr_ty), field_expr.1);
|
|
||||||
}
|
|
||||||
Ok(TypeKind::CustomType(struct_name.clone()))
|
|
||||||
}
|
}
|
||||||
|
ExprKind::Struct(_, items) => todo!("typechecking for struct expression"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -623,14 +499,13 @@ impl IndexedVariableReference {
|
|||||||
fn get_variable(
|
fn get_variable(
|
||||||
&self,
|
&self,
|
||||||
storage: &Storage<ScopeVariable>,
|
storage: &Storage<ScopeVariable>,
|
||||||
types: &Storage<TypeDefinitionKind>,
|
|
||||||
) -> Result<Option<ScopeVariable>, ErrorKind> {
|
) -> Result<Option<ScopeVariable>, ErrorKind> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => {
|
IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => {
|
||||||
Ok(storage.get(&name).cloned())
|
Ok(storage.get(&name).cloned())
|
||||||
}
|
}
|
||||||
IndexedVariableReferenceKind::ArrayIndex(inner_ref, _) => {
|
IndexedVariableReferenceKind::ArrayIndex(inner_ref, _) => {
|
||||||
if let Some(var) = inner_ref.get_variable(storage, types)? {
|
if let Some(var) = inner_ref.get_variable(storage)? {
|
||||||
match &var.ty {
|
match &var.ty {
|
||||||
TypeKind::Array(inner_ty, _) => Ok(Some(ScopeVariable {
|
TypeKind::Array(inner_ty, _) => Ok(Some(ScopeVariable {
|
||||||
ty: *inner_ty.clone(),
|
ty: *inner_ty.clone(),
|
||||||
@ -642,34 +517,8 @@ impl IndexedVariableReference {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IndexedVariableReferenceKind::StructIndex(var_ref, field_name) => {
|
IndexedVariableReferenceKind::StructIndex(indexed_variable_reference, _) => {
|
||||||
if let Some(var) = var_ref.get_variable(storage, types)? {
|
todo!("struct index refrence typecheck")
|
||||||
match &var.ty {
|
|
||||||
TypeKind::CustomType(type_name) => {
|
|
||||||
if let Some(kind) = types.get(type_name) {
|
|
||||||
match &kind {
|
|
||||||
TypeDefinitionKind::Struct(struct_type) => {
|
|
||||||
if let Some((_, field_ty)) =
|
|
||||||
struct_type.0.iter().find(|(n, _)| n == field_name)
|
|
||||||
{
|
|
||||||
Ok(Some(ScopeVariable {
|
|
||||||
ty: field_ty.clone(),
|
|
||||||
mutable: var.mutable,
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
Err(ErrorKind::NoSuchField(field_name.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(ErrorKind::NoSuchType(type_name.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(ErrorKind::TriedAccessingNonStruct(var.ty.clone())),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -801,15 +650,3 @@ impl Collapsable for ScopeFunction {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pass::Scope {
|
|
||||||
pub fn get_struct_type(&self, name: &String) -> Result<&StructType, ErrorKind> {
|
|
||||||
let ty = self
|
|
||||||
.types
|
|
||||||
.get(&name)
|
|
||||||
.ok_or(ErrorKind::NoSuchType(name.clone()))?;
|
|
||||||
match ty {
|
|
||||||
TypeDefinitionKind::Struct(struct_ty) => Ok(struct_ty),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -4,18 +4,17 @@
|
|||||||
//! must then be passed through TypeCheck with the same [`TypeRefs`] in order to
|
//! must then be passed through TypeCheck with the same [`TypeRefs`] in order to
|
||||||
//! place the correct types from the IDs and check that there are no issues.
|
//! place the correct types from the IDs and check that there are no issues.
|
||||||
|
|
||||||
use std::{convert::Infallible, iter};
|
use std::iter;
|
||||||
|
|
||||||
use crate::{mir::TypeKind, util::try_all};
|
use crate::{mir::TypeKind, util::try_all};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
pass::{self, Pass, PassState},
|
pass::{Pass, PassState},
|
||||||
typecheck::ErrorKind,
|
typecheck::ErrorKind,
|
||||||
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
|
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
|
||||||
types::{pick_return, ReturnType},
|
types::{pick_return, ReturnType},
|
||||||
Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression,
|
Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression,
|
||||||
IndexedVariableReference, IndexedVariableReferenceKind, Module, NamedVariableRef, ReturnKind,
|
IndexedVariableReference, Module, NamedVariableRef, ReturnKind, StmtKind,
|
||||||
StmtKind, StructType, TypeDefinitionKind,
|
|
||||||
TypeKind::*,
|
TypeKind::*,
|
||||||
VagueType::*,
|
VagueType::*,
|
||||||
};
|
};
|
||||||
@ -107,7 +106,7 @@ impl Block {
|
|||||||
}
|
}
|
||||||
StmtKind::Set(var, expr) => {
|
StmtKind::Set(var, expr) => {
|
||||||
// Get the TypeRef for this variable declaration
|
// Get the TypeRef for this variable declaration
|
||||||
let var_ref = var.find_hint(&state, &inner_hints)?;
|
let var_ref = var.find_hint(&inner_hints)?;
|
||||||
|
|
||||||
// If ok, update the MIR type to this TypeRef
|
// If ok, update the MIR type to this TypeRef
|
||||||
if let Some((_, var_ref)) = &var_ref {
|
if let Some((_, var_ref)) = &var_ref {
|
||||||
@ -156,15 +155,14 @@ impl Block {
|
|||||||
impl IndexedVariableReference {
|
impl IndexedVariableReference {
|
||||||
fn find_hint<'s>(
|
fn find_hint<'s>(
|
||||||
&self,
|
&self,
|
||||||
state: &PassState<ErrorKind>,
|
|
||||||
hints: &'s ScopeTypeRefs,
|
hints: &'s ScopeTypeRefs,
|
||||||
) -> Result<Option<(bool, TypeRef<'s>)>, ErrorKind> {
|
) -> Result<Option<(bool, TypeRef<'s>)>, ErrorKind> {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => {
|
super::IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => {
|
||||||
Ok(hints.find_var(&name))
|
Ok(hints.find_hint(&name))
|
||||||
}
|
}
|
||||||
IndexedVariableReferenceKind::ArrayIndex(inner, _) => {
|
super::IndexedVariableReferenceKind::ArrayIndex(inner, _) => {
|
||||||
if let Some((mutable, inner_ref)) = inner.find_hint(state, hints)? {
|
if let Some((mutable, inner_ref)) = inner.find_hint(hints)? {
|
||||||
// Check that the resolved type is at least an array, no
|
// Check that the resolved type is at least an array, no
|
||||||
// need for further resolution.
|
// need for further resolution.
|
||||||
let inner_ty = inner_ref.resolve_weak().unwrap();
|
let inner_ty = inner_ref.resolve_weak().unwrap();
|
||||||
@ -179,30 +177,8 @@ impl IndexedVariableReference {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IndexedVariableReferenceKind::StructIndex(inner, field_name) => {
|
super::IndexedVariableReferenceKind::StructIndex(indexed_variable_reference, _) => {
|
||||||
if let Some((mutable, inner_ref)) = inner.find_hint(state, hints)? {
|
todo!("struct index refrence type inference")
|
||||||
// Check that the resolved type is at least an array, no
|
|
||||||
// need for further resolution.
|
|
||||||
let inner_ty = inner_ref.resolve_weak().unwrap();
|
|
||||||
match &inner_ty {
|
|
||||||
CustomType(struct_name) => match state.scope.types.get(&struct_name) {
|
|
||||||
Some(kind) => match kind {
|
|
||||||
TypeDefinitionKind::Struct(struct_ty) => Ok(hints
|
|
||||||
.from_type(
|
|
||||||
&struct_ty
|
|
||||||
.get_field_ty(field_name)
|
|
||||||
.cloned()
|
|
||||||
.ok_or(ErrorKind::NoSuchField(self.get_name()))?,
|
|
||||||
)
|
|
||||||
.map(|v| (mutable, v))),
|
|
||||||
},
|
|
||||||
None => Err(ErrorKind::TriedAccessingNonStruct(inner_ty.clone())),
|
|
||||||
},
|
|
||||||
_ => Err(ErrorKind::TriedAccessingNonStruct(inner_ty)),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,7 +194,7 @@ impl Expression {
|
|||||||
ExprKind::Variable(var) => {
|
ExprKind::Variable(var) => {
|
||||||
// Find variable type
|
// Find variable type
|
||||||
let type_ref = type_refs
|
let type_ref = type_refs
|
||||||
.find_var(&var.1)
|
.find_hint(&var.1)
|
||||||
.map(|(_, hint)| hint)
|
.map(|(_, hint)| hint)
|
||||||
.ok_or(ErrorKind::VariableNotDefined(var.1.clone()));
|
.ok_or(ErrorKind::VariableNotDefined(var.1.clone()));
|
||||||
|
|
||||||
@ -363,52 +339,10 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::StructIndex(expression, type_kind, field_name) => {
|
ExprKind::StructIndex(expression, type_kind, _) => {
|
||||||
let expr_ty = expression.infer_types(state, type_refs)?;
|
todo!("type inference for struct indexes")
|
||||||
|
|
||||||
// Check that the resolved type is at least a struct, no
|
|
||||||
// need for further resolution.
|
|
||||||
let kind = expr_ty.resolve_weak().unwrap();
|
|
||||||
match kind {
|
|
||||||
CustomType(name) => {
|
|
||||||
let struct_ty = state.scope.get_struct_type(&name)?;
|
|
||||||
match struct_ty.get_field_ty(&field_name) {
|
|
||||||
Some(field_ty) => {
|
|
||||||
let mut elem_ty = type_refs.from_type(&type_kind).unwrap();
|
|
||||||
elem_ty.narrow(&type_refs.from_type(&field_ty).unwrap());
|
|
||||||
*type_kind = elem_ty.as_type().clone();
|
|
||||||
Ok(elem_ty)
|
|
||||||
}
|
|
||||||
None => Err(ErrorKind::NoSuchField(field_name.clone())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(ErrorKind::TriedAccessingNonStruct(kind)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExprKind::Struct(struct_name, fields) => {
|
|
||||||
let expected_struct_ty = state.scope.get_struct_type(&struct_name)?.clone();
|
|
||||||
for field in fields {
|
|
||||||
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
|
|
||||||
let field_ty = field.1.infer_types(state, type_refs);
|
|
||||||
dbg!(&field_ty, expected_field_ty);
|
|
||||||
if let Some(mut field_ty) = state.ok(field_ty, field.1 .1) {
|
|
||||||
field_ty.narrow(&type_refs.from_type(&expected_field_ty).unwrap());
|
|
||||||
dbg!(&field_ty);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
state.ok::<_, Infallible>(
|
|
||||||
Err(ErrorKind::NoSuchField(format!(
|
|
||||||
"{}.{}",
|
|
||||||
struct_name, field.0
|
|
||||||
))),
|
|
||||||
field.1 .1,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(type_refs
|
|
||||||
.from_type(&TypeKind::CustomType(struct_name.clone()))
|
|
||||||
.unwrap())
|
|
||||||
}
|
}
|
||||||
|
ExprKind::Struct(_, items) => todo!("type inference for struct expression"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use crate::mir::VagueType;
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
typecheck::{Collapsable, ErrorKind},
|
typecheck::{Collapsable, ErrorKind},
|
||||||
BinaryOperator, TypeDefinition, TypeKind,
|
BinaryOperator, TypeKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -209,12 +209,12 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_var(&'outer self, name: &String) -> Option<(bool, TypeRef<'outer>)> {
|
pub fn find_hint(&'outer self, name: &String) -> Option<(bool, TypeRef<'outer>)> {
|
||||||
self.variables
|
self.variables
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(name)
|
.get(name)
|
||||||
.map(|(mutable, idx)| (*mutable, TypeRef(idx.clone(), self)))
|
.map(|(mutable, idx)| (*mutable, TypeRef(idx.clone(), self)))
|
||||||
.or(self.outer.map(|o| o.find_var(name)).flatten())
|
.or(self.outer.map(|o| o.find_hint(name)).flatten())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn binop(
|
pub fn binop(
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::util::try_all;
|
use crate::util::try_all;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -31,16 +29,6 @@ impl TypeKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructType {
|
|
||||||
pub fn get_field_ty(&self, name: &String) -> Option<&TypeKind> {
|
|
||||||
self.0.iter().find(|(n, _)| n == name).map(|(_, ty)| ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_field_ty_mut(&mut self, name: &String) -> Option<&mut TypeKind> {
|
|
||||||
self.0.iter_mut().find(|(n, _)| n == name).map(|(_, ty)| ty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ReturnType {
|
pub trait ReturnType {
|
||||||
/// Return the return type of this node
|
/// Return the return type of this node
|
||||||
fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther>;
|
fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther>;
|
||||||
@ -120,8 +108,18 @@ impl ReturnType for Expression {
|
|||||||
TypeKind::Array(Box::new(first.1), expressions.len() as u64),
|
TypeKind::Array(Box::new(first.1), expressions.len() as u64),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
StructIndex(_, type_kind, _) => Ok((ReturnKind::Soft, type_kind.clone())),
|
StructIndex(expression, type_kind, _) => todo!("todo return type for struct index"),
|
||||||
Struct(name, _) => Ok((ReturnKind::Soft, TypeKind::CustomType(name.clone()))),
|
Struct(name, items) => {
|
||||||
|
let f_types = try_all(items.iter().map(|e| e.1.return_type()).collect())
|
||||||
|
.map_err(|e| unsafe { e.get_unchecked(0).clone() })?
|
||||||
|
.iter()
|
||||||
|
.map(|r| r.1.clone())
|
||||||
|
.collect();
|
||||||
|
Ok((
|
||||||
|
ReturnKind::Soft,
|
||||||
|
TypeKind::CustomType(name.clone(), CustomTypeKind::Struct(f_types)),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,5 +11,5 @@ fn main() -> u32 {
|
|||||||
second: 3,
|
second: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
return value.second;
|
return Test.second;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user