cl-typeck: Progress population and categorization

This commit is contained in:
John 2025-05-05 04:54:33 -04:00
parent 4228324ab3
commit 09fdb14d79
6 changed files with 95 additions and 58 deletions

View File

@ -66,12 +66,9 @@ fn write_adt(adt: &Adt, h: &Entry, f: &mut impl Write) -> fmt::Result {
let mut variants = variants.iter();
separate(", ", || {
variants.next().map(|(name, def)| {
move |f: &mut Delimit<_>| match def {
Some(def) => {
write!(f, "{name}: ")?;
write_name_or(h.with_id(*def), f)
}
None => write!(f, "{name}"),
move |f: &mut Delimit<_>| {
write!(f, "{name}: ")?;
write_name_or(h.with_id(*def), f)
}
})
})(f.delimit_with("enum {", "}"))

View File

@ -31,7 +31,7 @@ pub fn categorize(table: &mut Table, node: Handle) -> CatResult<()> {
Source::Module(_) => Ok(()),
Source::Alias(a) => cat_alias(table, node, a),
Source::Enum(e) => cat_enum(table, node, e),
Source::Variant(_) => Ok(()),
Source::Variant(v) => cat_variant(table, node, v),
Source::Struct(s) => cat_struct(table, node, s),
Source::Const(c) => cat_const(table, node, c),
Source::Static(s) => cat_static(table, node, s),
@ -98,51 +98,51 @@ fn cat_member(
Ok((*name, *vis, ty.evaluate(table, node)?))
}
fn cat_enum<'a>(table: &mut Table<'a>, node: Handle, e: &'a Enum) -> CatResult<()> {
let Enum { name: _, gens: _, variants: kind } = e;
// TODO: Genereics
let kind = match kind {
None => TypeKind::Adt(Adt::Enum(vec![])),
Some(variants) => {
let mut out_vars = vec![];
for v in variants {
out_vars.push(cat_variant(table, node, v)?)
}
TypeKind::Adt(Adt::Enum(out_vars))
}
};
fn cat_enum<'a>(_table: &mut Table<'a>, _node: Handle, e: &'a Enum) -> CatResult<()> {
let Enum { name: _, gens: _, variants: _ } = e;
table.set_ty(node, kind);
// table.set_ty(node, kind);
Ok(())
}
fn cat_variant<'a>(
table: &mut Table<'a>,
node: Handle,
v: &'a Variant,
) -> CatResult<(Sym, Option<Handle>)> {
fn cat_variant<'a>(table: &mut Table<'a>, node: Handle, v: &'a Variant) -> CatResult<()> {
let Variant { name, kind } = v;
let parent = table.parent(node).copied().unwrap_or(table.root());
table.add_child(parent, *name, node);
match kind {
VariantKind::Plain => Ok((*name, None)),
VariantKind::CLike(c) => todo!("enum-variant constant {c}"),
VariantKind::Plain => {
table.set_ty(node, TypeKind::Instance(parent));
Ok(())
}
VariantKind::CLike(c) => {
table.set_body(node, c);
table.set_ty(node, TypeKind::Instance(parent));
Ok(())
}
VariantKind::Tuple(ty) => {
let ty = ty
.evaluate(table, node)
.map_err(|e| Error::TypeEval(e, " while categorizing a variant"))?;
Ok((*name, Some(ty)))
table.set_ty(node, TypeKind::Instance(ty));
Ok(())
}
VariantKind::Struct(members) => {
let mut out = vec![];
for m in members {
out.push(cat_member(table, node, m)?)
}
let kind = TypeKind::Adt(Adt::Struct(out));
for StructMember { vis, name, ty } in members {
let ty = ty.evaluate(table, node)?;
out.push((*name, *vis, ty));
let mut h = node.to_entry_mut(table);
let mut variant = h.new_entry(NodeKind::Type);
variant.set_source(Source::Variant(v));
variant.set_ty(kind);
Ok((*name, Some(variant.id())))
let mut this = node.to_entry_mut(table);
let mut child = this.new_entry(NodeKind::Type);
child.set_source(Source::Variant(v));
child.set_ty(TypeKind::Instance(ty));
let child = child.id();
this.add_child(*name, child);
}
table.set_ty(node, TypeKind::Adt(Adt::Struct(out)));
Ok(())
}
}
}

View File

@ -274,9 +274,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
&TypeKind::Array(h, _) => self.is_generic(h),
&TypeKind::Instance(h) => self.is_generic(h),
TypeKind::Primitive(_) => false,
TypeKind::Adt(Adt::Enum(tys)) => tys
.iter()
.any(|(_, ty)| ty.is_some_and(|ty| self.is_generic(ty))),
TypeKind::Adt(Adt::Enum(tys)) => tys.iter().any(|(_, ty)| self.is_generic(*ty)),
TypeKind::Adt(Adt::Struct(tys)) => tys.iter().any(|&(_, _, ty)| self.is_generic(ty)),
TypeKind::Adt(Adt::TupleStruct(tys)) => tys.iter().any(|&(_, ty)| self.is_generic(ty)),
TypeKind::Adt(Adt::UnitStruct) => false,
@ -313,7 +311,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
TypeKind::Adt(Adt::Enum(tys)) => {
let tys = tys
.into_iter()
.map(|(name, ty)| (name, ty.map(|ty| self.deep_clone(ty))))
.map(|(name, ty)| (name, self.deep_clone(ty)))
.collect();
self.table.anon_type(TypeKind::Adt(Adt::Enum(tys)))
}
@ -385,9 +383,9 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
};
match ty {
TypeKind::Instance(other) => self.occurs_in(this, *other),
TypeKind::Adt(Adt::Enum(items)) => items
.iter()
.any(|(_, i)| i.is_some_and(|other| self.occurs_in(this, other))),
TypeKind::Adt(Adt::Enum(items)) => {
items.iter().any(|(_, other)| self.occurs_in(this, *other))
}
TypeKind::Adt(Adt::Struct(items)) => items
.iter()
.any(|(_, _, other)| self.occurs_in(this, *other)),
@ -462,10 +460,9 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
if ia.len() == ib.len() =>
{
for ((na, a), (nb, b)) in ia.clone().into_iter().zip(ib.clone().into_iter()) {
if na != nb || a.is_some() != b.is_some() {
if na != nb {
return Err(InferenceError::Mismatch(ah, bh));
}
let (Some(a), Some(b)) = (a, b) else { continue };
self.unify(a, b)?;
}
Ok(())

View File

@ -4,8 +4,12 @@ use crate::{
handle::Handle,
source::Source,
table::{NodeKind, Table},
type_kind::{Primitive, TypeKind},
};
use cl_ast::{
ItemKind, Sym,
ast_visitor::{Visit, Walk},
};
use cl_ast::{ItemKind, Sym, ast_visitor::Visit};
#[derive(Debug)]
pub struct Populator<'t, 'a> {
@ -60,6 +64,17 @@ impl<'a> Visit<'a> for Populator<'_, 'a> {
}
}
fn visit_generics(&mut self, value: &'a cl_ast::Generics) {
let cl_ast::Generics { vars } = value;
for var in vars {
let mut entry = self.inner.new_entry(NodeKind::Type);
entry.set_ty(TypeKind::Variable);
let id = entry.id();
self.inner.add_child(*var, id);
}
}
fn visit_alias(&mut self, a: &'a cl_ast::Alias) {
let cl_ast::Alias { name, from } = a;
self.inner.set_source(Source::Alias(a));
@ -98,11 +113,12 @@ impl<'a> Visit<'a> for Populator<'_, 'a> {
}
fn visit_function(&mut self, f: &'a cl_ast::Function) {
let cl_ast::Function { name, gens: _, sign, bind, body } = f;
let cl_ast::Function { name, gens, sign, bind, body } = f;
// TODO: populate generics?
self.inner.set_source(Source::Function(f));
self.set_name(*name);
self.visit(gens);
self.visit(sign);
self.visit(bind);
@ -113,21 +129,51 @@ impl<'a> Visit<'a> for Populator<'_, 'a> {
}
fn visit_struct(&mut self, s: &'a cl_ast::Struct) {
let cl_ast::Struct { name, gens: _, kind } = s;
// TODO: populate generics?
let cl_ast::Struct { name, gens, kind } = s;
self.inner.set_source(Source::Struct(s));
self.set_name(*name);
self.visit(gens);
self.visit(kind);
}
fn visit_enum(&mut self, e: &'a cl_ast::Enum) {
let cl_ast::Enum { name, gens: _, variants } = e;
// TODO: populate generics?
let cl_ast::Enum { name, gens, variants } = e;
self.inner.set_source(Source::Enum(e));
self.set_name(*name);
self.visit(gens);
self.visit(variants);
let mut children = Vec::new();
for variant in variants.iter().flatten() {
let mut entry = self.new_entry(NodeKind::Type);
variant.visit_in(&mut entry);
children.push((variant.name, entry.inner.id()));
}
self.inner
.set_ty(TypeKind::Adt(crate::type_kind::Adt::Enum(children)));
}
fn visit_variant(&mut self, value: &'a cl_ast::Variant) {
let cl_ast::Variant { name, kind } = value;
let mut entry = self.new_entry(NodeKind::Type);
entry.inner.set_source(Source::Variant(value));
entry.visit(kind);
let child = entry.inner.id();
self.inner.add_child(*name, child);
}
fn visit_variant_kind(&mut self, value: &'a cl_ast::VariantKind) {
match value {
cl_ast::VariantKind::Plain => self.inner.set_ty(TypeKind::Empty),
cl_ast::VariantKind::CLike(body) => {
self.inner.set_body(body);
self.inner.set_ty(TypeKind::Primitive(Primitive::Integer))
}
cl_ast::VariantKind::Tuple(_) => None,
cl_ast::VariantKind::Struct(_) => None,
};
}
fn visit_impl(&mut self, i: &'a cl_ast::Impl) {

View File

@ -42,7 +42,7 @@ pub enum TypeKind {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Adt {
/// A union-like enum type
Enum(Vec<(Sym, Option<Handle>)>),
Enum(Vec<(Sym, Handle)>),
/// A structural product type with named members
Struct(Vec<(Sym, Visibility, Handle)>),

View File

@ -38,10 +38,7 @@ impl Display for Adt {
let mut variants = variants.iter();
separate(", ", || {
let (name, def) = variants.next()?;
Some(move |f: &mut Delimit<_>| match def {
Some(def) => write!(f, "{name}: #{def}"),
None => write!(f, "{name}"),
})
Some(move |f: &mut Delimit<_>| write!(f, "{name}: #{def}"))
})(f.delimit_with("enum {", "}"))
}
Adt::Struct(members) => {