schala/schala-lang/language/src/type_inference/mod.rs

150 lines
3.7 KiB
Rust
Raw Normal View History

use std::{collections::HashMap, convert::From};
//use crate::symbol_table::Fqsn;
use crate::{
ast::TypeIdentifier,
identifier::{define_id_kind, Id, IdStore},
};
define_id_kind!(TypeItem);
pub type TypeId = Id<TypeItem>;
pub struct TypeContext {
defined_types: HashMap<TypeId, DefinedType>,
type_id_store: IdStore<TypeItem>,
}
impl TypeContext {
pub fn new() -> Self {
Self { defined_types: HashMap::new(), type_id_store: IdStore::new() }
}
pub fn register_type(&mut self, builder: TypeBuilder) -> TypeId {
let type_id = self.type_id_store.fresh();
let defined = DefinedType {
name: builder.name,
//TODO come up with a canonical tag order
variants: builder.variants.into_iter().map(|builder| Variant { name: builder.name }).collect(),
};
self.defined_types.insert(type_id, defined);
type_id
}
pub fn variant_local_name(&self, type_id: &TypeId, tag: u32) -> Option<&str> {
self.defined_types
.get(type_id)
.and_then(|defined| defined.variants.get(tag as usize))
.map(|variant| variant.name.as_ref())
}
}
/// A type defined in program source code, as opposed to a builtin.
#[allow(dead_code)]
struct DefinedType {
name: String,
//fqsn: Fqsn,
// the variants are in this list according to tag order
variants: Vec<Variant>,
}
struct Variant {
name: String,
}
/// Represents a type mentioned as a member of another type during the type registration process.
/// It may not have been registered itself in the relevant context.
#[allow(dead_code)]
pub struct PendingType {
inner: TypeIdentifier,
}
impl From<&TypeIdentifier> for PendingType {
fn from(type_identifier: &TypeIdentifier) -> Self {
Self { inner: type_identifier.clone() }
}
}
pub struct TypeBuilder {
name: String,
variants: Vec<VariantBuilder>,
}
impl TypeBuilder {
pub fn new(name: &str) -> Self {
Self { name: name.to_string(), variants: vec![] }
}
pub fn add_variant(&mut self, vb: VariantBuilder) {
self.variants.push(vb);
}
}
pub struct VariantBuilder {
name: String,
members: Vec<VariantMember>,
}
impl VariantBuilder {
pub fn new(name: &str) -> Self {
Self { name: name.to_string(), members: vec![] }
}
2021-10-27 15:39:09 -07:00
pub fn add_member(&mut self, member_ty: PendingType) {
self.members.push(VariantMember::Pending(member_ty));
2021-10-27 15:39:09 -07:00
}
// You can't call this and `add_member` on the same fn, there should be a runtime error when
// that's detected.
pub fn add_record_member(&mut self, name: &str, ty: PendingType) {
self.members.push(VariantMember::KeyVal(name.to_string(), ty));
}
}
enum VariantMember {
Pending(PendingType),
KeyVal(String, PendingType),
}
#[derive(Debug, Clone)]
pub struct TypeError {
pub msg: String,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TypeConst {
Unit,
Nat,
Int,
Float,
StringT,
Bool,
Ordering,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub enum Type {
Const(TypeConst),
//Var(TypeVar),
Arrow { params: Vec<Type>, ret: Box<Type> },
Compound { ty_name: String, args: Vec<Type> },
}
macro_rules! ty {
($type_name:ident) => {
Type::Const(crate::type_inference::TypeConst::$type_name)
};
($t1:ident -> $t2:ident) => {
Type::Arrow { params: vec![ty!($t1)], ret: box ty!($t2) }
};
($t1:ident -> $t2:ident -> $t3:ident) => {
Type::Arrow { params: vec![ty!($t1), ty!($t2)], ret: box ty!($t3) }
};
($type_list:ident, $ret_type:ident) => {
Type::Arrow { params: $type_list, ret: box $ret_type }
};
}