idk man..

This commit is contained in:
janis 2025-09-19 20:12:21 +02:00
parent 82d2eed09a
commit 2293b514cf
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
2 changed files with 162 additions and 12 deletions

View file

@ -5,30 +5,43 @@
// Visitor pattern has lots of unused arguments // Visitor pattern has lots of unused arguments
#![allow(unused_variables)] #![allow(unused_variables)]
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use crate::ast2::tag::{AstNode, AstNodeExt};
use super::{Ast, Index, intern, visitor::AstVisitorTrait}; use super::{Ast, Index, intern, visitor::AstVisitorTrait};
type Id = u32; type Id = u32;
enum Type { trait TypeVariance {
Reified(intern::Index), type T;
Variable(Id), type Opposite;
}
#[derive(Debug, Clone)]
enum TypeHead<T: TypeVariance> {
Real(intern::Index),
Function { args: Vec<T::T>, ret: T::Opposite },
} }
/// Variance of a type parameter or constraint. /// Variance of a type parameter or constraint.
/// A function of type `A -> B` is covariant in `B` and contravariant in `A`. /// A function of type `A -> B` is covariant in `B` and contravariant in `A`.
/// This means that a type `T` may be substituted for `A` if `T` is a subtype of `A`, but /// This means that a type `T` may be substituted for `A` if `T` is a subtype of
/// a type `T` may only be substituted for `B` if `T` is a supertype of `B`. /// `A`, that is, every `T` is also an `A`,
/// but a type `T` may only be substituted for `B` if `T` is a supertype of `B`,
/// that is, every `B` is also a `T`.
/// ///
/// Namely, in a type system with `int` and `nat <: int`, for a function `f: int /// Namely, in a type system with `int` and `nat <: int`, for a function `f: int
/// -> int` in the expression `let u: int = 3; let t: nat = f(u);`, `u` may /// -> int` in the expression `let u: int = 3; let t: nat = f(u);`, `u` may
/// safely be used as an argument to `f` because `nat <: int`, but `f(u`)` may /// safely be used as an argument to `f` because `nat <: int`, but `f(u`)` may
/// not be assigned to `t` because `int <: nat` is not true. /// not be assigned to `t` because `int <: nat` is not true.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
enum Variance { enum Variance {
#[doc(alias = "Positive")] /// A Positive, or union relationship between types.
/// used in value-places.
Covariant, Covariant,
#[doc(alias = "Negative")] /// A Negative, or intersection relationship between types.
/// used in use-places.
Contravariant, Contravariant,
} }
@ -37,27 +50,81 @@ struct Value(Id);
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
struct Use(Id); struct Use(Id);
impl TypeVariance for Value {
type T = Value;
type Opposite = Use;
}
impl TypeVariance for Use {
type T = Use;
type Opposite = Value;
}
/// Typechecking error. /// Typechecking error.
#[derive(Debug, Clone, thiserror::Error)] #[derive(Debug, Clone, thiserror::Error)]
enum Error { enum Error {
#[error("Unimplemented feature")] #[error("Unimplemented feature")]
Unimplemented, Unimplemented,
#[error("{0}")]
StringError(String),
} }
type Result<T> = std::result::Result<T, Error>; type Result<T> = std::result::Result<T, Error>;
struct Bindings { struct Bindings {
inner: HashMap<super::Index, Value>, next_id: Id,
inner: HashMap<super::Index, Id>,
bounds: HashSet<(Id, Id, Variance)>,
types: HashMap<Id, intern::Index>,
}
impl Bindings {
fn new() -> Self {
Bindings {
next_id: 1,
inner: HashMap::new(),
bounds: HashSet::new(),
types: HashMap::new(),
}
}
fn new_id(&mut self) -> Id {
let id = self.next_id;
self.next_id += 1;
id
}
fn get_or_create(&mut self, idx: super::Index) -> Id {
self.inner.get(&idx).copied().unwrap_or_else(|| {
let id = self.new_id();
self.inner.insert(idx, id);
id
})
}
/// retrieves the type Id for the given ast node.
fn get(&self, idx: super::Index) -> Option<Id> {
self.inner.get(&idx).copied()
}
/// inserts a proper type for `id`.
fn insert_type(&mut self, id: Id, ty: intern::Index) {
self.types.insert(id, ty);
}
} }
struct TypeChecker<'a> { struct TypeChecker<'a> {
pool: &'a mut intern::InternPool, pool: &'a mut intern::InternPool,
bindings: Bindings,
} }
// Core // Core
impl TypeChecker<'_> { impl TypeChecker<'_> {
pub fn new(pool: &mut intern::InternPool) -> TypeChecker { pub fn new(pool: &mut intern::InternPool) -> TypeChecker {
TypeChecker { pool } TypeChecker {
pool,
bindings: Bindings::new(),
}
} }
fn var(&mut self) -> (Value, Use) { fn var(&mut self) -> (Value, Use) {
@ -73,6 +140,33 @@ impl<'a> AstVisitorTrait<&'a Ast> for TypeChecker<'_> {
const UNIMPL: Self::Error = Error::Unimplemented; const UNIMPL: Self::Error = Error::Unimplemented;
fn visit_interned_type_impl(
&mut self,
ast: &'a Ast,
idx: Index,
intern: intern::Index,
) -> std::result::Result<Self::Value, Self::Error> {
let id = self.bindings.get_or_create(idx);
match self.pool.get_key(intern) {
intern::Key::SimpleType {
ty: intern::SimpleType::ComptimeInt,
} => {
// This is a type variable.
}
intern::Key::SimpleType { .. }
| intern::Key::PointerType { .. }
| intern::Key::ArrayType { .. }
| intern::Key::FunctionType { .. }
| intern::Key::StructType { .. } => {
// This is a real type.
self.bindings.insert_type(id, intern);
}
_ => unreachable!(),
}
Ok(Value(id))
}
fn visit_constant_impl( fn visit_constant_impl(
&mut self, &mut self,
ast: &'a Ast, ast: &'a Ast,
@ -80,8 +174,30 @@ impl<'a> AstVisitorTrait<&'a Ast> for TypeChecker<'_> {
ty: Index, ty: Index,
value: intern::Index, value: intern::Index,
) -> std::result::Result<Self::Value, Self::Error> { ) -> std::result::Result<Self::Value, Self::Error> {
// constants may be of type `comptime_int`, which is a special type that // get type from the pool
// cannot exist at runtime.
let AstNode::InternedType { intern } = ast.get_ast_node(ty) else {
panic!(
"Expected an interned type node, got {:?}",
ast.get_ast_node(ty)
);
};
match self.pool.get_key(intern) {
intern::Key::SimpleType {
ty: intern::SimpleType::ComptimeInt,
} => {
// This is a type variable.
}
intern::Key::SimpleType { .. }
| intern::Key::PointerType { .. }
| intern::Key::ArrayType { .. }
| intern::Key::FunctionType { .. }
| intern::Key::StructType { .. } => {
// This is a real type.
}
_ => unreachable!(),
}
todo!() todo!()
} }

34
src/ast2/internable.rs Normal file
View file

@ -0,0 +1,34 @@
use super::*;
use core::hash::Hash;
use std::hash::Hasher;
// Types implementing this trait can be stored in the internpool.
trait KeyTrait: Hash + Eq {
const TAG: Tag;
fn serialise(self, pool: &mut InternPool);
fn deserialise(index: Index, pool: &mut InternPool) -> Self;
}
impl KeyTrait for String {
const TAG: Tag = Tag::String;
fn serialise(self, pool: &mut InternPool) {
todo!()
}
fn deserialise(index: Index, pool: &mut InternPool) -> Self {
// let mut hasher = std::hash::DefaultHasher::new();
// core::any::TypeId::of::<Self>().hash(&mut hasher);
// let tag = hasher.finish() as u32;
let item = pool.get_item(index).unwrap();
assert_eq!(item.tag, Self::TAG);
let start = pool.words[item.idx()] as usize;
let len = pool.words[item.idx() + 1] as usize;
let str = unsafe {
let bytes = &pool.strings[start..start + len];
std::str::from_utf8_unchecked(bytes)
};
str.to_owned()
}
}