cl-typeck: Progress population and categorization
This commit is contained in:
		@@ -66,12 +66,9 @@ fn write_adt(adt: &Adt, h: &Entry, f: &mut impl Write) -> fmt::Result {
 | 
				
			|||||||
            let mut variants = variants.iter();
 | 
					            let mut variants = variants.iter();
 | 
				
			||||||
            separate(", ", || {
 | 
					            separate(", ", || {
 | 
				
			||||||
                variants.next().map(|(name, def)| {
 | 
					                variants.next().map(|(name, def)| {
 | 
				
			||||||
                    move |f: &mut Delimit<_>| match def {
 | 
					                    move |f: &mut Delimit<_>| {
 | 
				
			||||||
                        Some(def) => {
 | 
					                        write!(f, "{name}: ")?;
 | 
				
			||||||
                            write!(f, "{name}: ")?;
 | 
					                        write_name_or(h.with_id(*def), f)
 | 
				
			||||||
                            write_name_or(h.with_id(*def), f)
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        None => write!(f, "{name}"),
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            })(f.delimit_with("enum {", "}"))
 | 
					            })(f.delimit_with("enum {", "}"))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,7 @@ pub fn categorize(table: &mut Table, node: Handle) -> CatResult<()> {
 | 
				
			|||||||
        Source::Module(_) => Ok(()),
 | 
					        Source::Module(_) => Ok(()),
 | 
				
			||||||
        Source::Alias(a) => cat_alias(table, node, a),
 | 
					        Source::Alias(a) => cat_alias(table, node, a),
 | 
				
			||||||
        Source::Enum(e) => cat_enum(table, node, e),
 | 
					        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::Struct(s) => cat_struct(table, node, s),
 | 
				
			||||||
        Source::Const(c) => cat_const(table, node, c),
 | 
					        Source::Const(c) => cat_const(table, node, c),
 | 
				
			||||||
        Source::Static(s) => cat_static(table, node, s),
 | 
					        Source::Static(s) => cat_static(table, node, s),
 | 
				
			||||||
@@ -98,51 +98,51 @@ fn cat_member(
 | 
				
			|||||||
    Ok((*name, *vis, ty.evaluate(table, node)?))
 | 
					    Ok((*name, *vis, ty.evaluate(table, node)?))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn cat_enum<'a>(table: &mut Table<'a>, node: Handle, e: &'a Enum) -> CatResult<()> {
 | 
					fn cat_enum<'a>(_table: &mut Table<'a>, _node: Handle, e: &'a Enum) -> CatResult<()> {
 | 
				
			||||||
    let Enum { name: _, gens: _, variants: kind } = e;
 | 
					    let Enum { name: _, gens: _, variants: _ } = 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))
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    table.set_ty(node, kind);
 | 
					    // table.set_ty(node, kind);
 | 
				
			||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn cat_variant<'a>(
 | 
					fn cat_variant<'a>(table: &mut Table<'a>, node: Handle, v: &'a Variant) -> CatResult<()> {
 | 
				
			||||||
    table: &mut Table<'a>,
 | 
					 | 
				
			||||||
    node: Handle,
 | 
					 | 
				
			||||||
    v: &'a Variant,
 | 
					 | 
				
			||||||
) -> CatResult<(Sym, Option<Handle>)> {
 | 
					 | 
				
			||||||
    let Variant { name, kind } = v;
 | 
					    let Variant { name, kind } = v;
 | 
				
			||||||
 | 
					    let parent = table.parent(node).copied().unwrap_or(table.root());
 | 
				
			||||||
 | 
					    table.add_child(parent, *name, node);
 | 
				
			||||||
    match kind {
 | 
					    match kind {
 | 
				
			||||||
        VariantKind::Plain => Ok((*name, None)),
 | 
					        VariantKind::Plain => {
 | 
				
			||||||
        VariantKind::CLike(c) => todo!("enum-variant constant {c}"),
 | 
					            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) => {
 | 
					        VariantKind::Tuple(ty) => {
 | 
				
			||||||
            let ty = ty
 | 
					            let ty = ty
 | 
				
			||||||
                .evaluate(table, node)
 | 
					                .evaluate(table, node)
 | 
				
			||||||
                .map_err(|e| Error::TypeEval(e, " while categorizing a variant"))?;
 | 
					                .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) => {
 | 
					        VariantKind::Struct(members) => {
 | 
				
			||||||
            let mut out = vec![];
 | 
					            let mut out = vec![];
 | 
				
			||||||
            for m in members {
 | 
					            for StructMember { vis, name, ty } in members {
 | 
				
			||||||
                out.push(cat_member(table, node, m)?)
 | 
					                let ty = ty.evaluate(table, node)?;
 | 
				
			||||||
            }
 | 
					                out.push((*name, *vis, ty));
 | 
				
			||||||
            let kind = TypeKind::Adt(Adt::Struct(out));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let mut h = node.to_entry_mut(table);
 | 
					                let mut this = node.to_entry_mut(table);
 | 
				
			||||||
            let mut variant = h.new_entry(NodeKind::Type);
 | 
					                let mut child = this.new_entry(NodeKind::Type);
 | 
				
			||||||
            variant.set_source(Source::Variant(v));
 | 
					                child.set_source(Source::Variant(v));
 | 
				
			||||||
            variant.set_ty(kind);
 | 
					                child.set_ty(TypeKind::Instance(ty));
 | 
				
			||||||
            Ok((*name, Some(variant.id())))
 | 
					
 | 
				
			||||||
 | 
					                let child = child.id();
 | 
				
			||||||
 | 
					                this.add_child(*name, child);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            table.set_ty(node, TypeKind::Adt(Adt::Struct(out)));
 | 
				
			||||||
 | 
					            Ok(())
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -274,9 +274,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
 | 
				
			|||||||
            &TypeKind::Array(h, _) => self.is_generic(h),
 | 
					            &TypeKind::Array(h, _) => self.is_generic(h),
 | 
				
			||||||
            &TypeKind::Instance(h) => self.is_generic(h),
 | 
					            &TypeKind::Instance(h) => self.is_generic(h),
 | 
				
			||||||
            TypeKind::Primitive(_) => false,
 | 
					            TypeKind::Primitive(_) => false,
 | 
				
			||||||
            TypeKind::Adt(Adt::Enum(tys)) => tys
 | 
					            TypeKind::Adt(Adt::Enum(tys)) => tys.iter().any(|(_, ty)| self.is_generic(*ty)),
 | 
				
			||||||
                .iter()
 | 
					 | 
				
			||||||
                .any(|(_, ty)| ty.is_some_and(|ty| self.is_generic(ty))),
 | 
					 | 
				
			||||||
            TypeKind::Adt(Adt::Struct(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::TupleStruct(tys)) => tys.iter().any(|&(_, ty)| self.is_generic(ty)),
 | 
				
			||||||
            TypeKind::Adt(Adt::UnitStruct) => false,
 | 
					            TypeKind::Adt(Adt::UnitStruct) => false,
 | 
				
			||||||
@@ -313,7 +311,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
 | 
				
			|||||||
            TypeKind::Adt(Adt::Enum(tys)) => {
 | 
					            TypeKind::Adt(Adt::Enum(tys)) => {
 | 
				
			||||||
                let tys = tys
 | 
					                let tys = tys
 | 
				
			||||||
                    .into_iter()
 | 
					                    .into_iter()
 | 
				
			||||||
                    .map(|(name, ty)| (name, ty.map(|ty| self.deep_clone(ty))))
 | 
					                    .map(|(name, ty)| (name, self.deep_clone(ty)))
 | 
				
			||||||
                    .collect();
 | 
					                    .collect();
 | 
				
			||||||
                self.table.anon_type(TypeKind::Adt(Adt::Enum(tys)))
 | 
					                self.table.anon_type(TypeKind::Adt(Adt::Enum(tys)))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -385,9 +383,9 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
        match ty {
 | 
					        match ty {
 | 
				
			||||||
            TypeKind::Instance(other) => self.occurs_in(this, *other),
 | 
					            TypeKind::Instance(other) => self.occurs_in(this, *other),
 | 
				
			||||||
            TypeKind::Adt(Adt::Enum(items)) => items
 | 
					            TypeKind::Adt(Adt::Enum(items)) => {
 | 
				
			||||||
                .iter()
 | 
					                items.iter().any(|(_, other)| self.occurs_in(this, *other))
 | 
				
			||||||
                .any(|(_, i)| i.is_some_and(|other| self.occurs_in(this, other))),
 | 
					            }
 | 
				
			||||||
            TypeKind::Adt(Adt::Struct(items)) => items
 | 
					            TypeKind::Adt(Adt::Struct(items)) => items
 | 
				
			||||||
                .iter()
 | 
					                .iter()
 | 
				
			||||||
                .any(|(_, _, other)| self.occurs_in(this, *other)),
 | 
					                .any(|(_, _, other)| self.occurs_in(this, *other)),
 | 
				
			||||||
@@ -462,10 +460,9 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
 | 
				
			|||||||
                if ia.len() == ib.len() =>
 | 
					                if ia.len() == ib.len() =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                for ((na, a), (nb, b)) in ia.clone().into_iter().zip(ib.clone().into_iter()) {
 | 
					                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));
 | 
					                        return Err(InferenceError::Mismatch(ah, bh));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    let (Some(a), Some(b)) = (a, b) else { continue };
 | 
					 | 
				
			||||||
                    self.unify(a, b)?;
 | 
					                    self.unify(a, b)?;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                Ok(())
 | 
					                Ok(())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,8 +4,12 @@ use crate::{
 | 
				
			|||||||
    handle::Handle,
 | 
					    handle::Handle,
 | 
				
			||||||
    source::Source,
 | 
					    source::Source,
 | 
				
			||||||
    table::{NodeKind, Table},
 | 
					    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)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct Populator<'t, 'a> {
 | 
					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) {
 | 
					    fn visit_alias(&mut self, a: &'a cl_ast::Alias) {
 | 
				
			||||||
        let cl_ast::Alias { name, from } = a;
 | 
					        let cl_ast::Alias { name, from } = a;
 | 
				
			||||||
        self.inner.set_source(Source::Alias(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) {
 | 
					    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?
 | 
					        // TODO: populate generics?
 | 
				
			||||||
        self.inner.set_source(Source::Function(f));
 | 
					        self.inner.set_source(Source::Function(f));
 | 
				
			||||||
        self.set_name(*name);
 | 
					        self.set_name(*name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.visit(gens);
 | 
				
			||||||
        self.visit(sign);
 | 
					        self.visit(sign);
 | 
				
			||||||
        self.visit(bind);
 | 
					        self.visit(bind);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -113,21 +129,51 @@ impl<'a> Visit<'a> for Populator<'_, 'a> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn visit_struct(&mut self, s: &'a cl_ast::Struct) {
 | 
					    fn visit_struct(&mut self, s: &'a cl_ast::Struct) {
 | 
				
			||||||
        let cl_ast::Struct { name, gens: _, kind } = s;
 | 
					        let cl_ast::Struct { name, gens, kind } = s;
 | 
				
			||||||
        // TODO: populate generics?
 | 
					 | 
				
			||||||
        self.inner.set_source(Source::Struct(s));
 | 
					        self.inner.set_source(Source::Struct(s));
 | 
				
			||||||
        self.set_name(*name);
 | 
					        self.set_name(*name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.visit(gens);
 | 
				
			||||||
        self.visit(kind);
 | 
					        self.visit(kind);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn visit_enum(&mut self, e: &'a cl_ast::Enum) {
 | 
					    fn visit_enum(&mut self, e: &'a cl_ast::Enum) {
 | 
				
			||||||
        let cl_ast::Enum { name, gens: _, variants } = e;
 | 
					        let cl_ast::Enum { name, gens, variants } = e;
 | 
				
			||||||
        // TODO: populate generics?
 | 
					 | 
				
			||||||
        self.inner.set_source(Source::Enum(e));
 | 
					        self.inner.set_source(Source::Enum(e));
 | 
				
			||||||
        self.set_name(*name);
 | 
					        self.set_name(*name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.visit(gens);
 | 
				
			||||||
        self.visit(variants);
 | 
					        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) {
 | 
					    fn visit_impl(&mut self, i: &'a cl_ast::Impl) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,7 +42,7 @@ pub enum TypeKind {
 | 
				
			|||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 | 
					#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 | 
				
			||||||
pub enum Adt {
 | 
					pub enum Adt {
 | 
				
			||||||
    /// A union-like enum type
 | 
					    /// A union-like enum type
 | 
				
			||||||
    Enum(Vec<(Sym, Option<Handle>)>),
 | 
					    Enum(Vec<(Sym, Handle)>),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// A structural product type with named members
 | 
					    /// A structural product type with named members
 | 
				
			||||||
    Struct(Vec<(Sym, Visibility, Handle)>),
 | 
					    Struct(Vec<(Sym, Visibility, Handle)>),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,10 +38,7 @@ impl Display for Adt {
 | 
				
			|||||||
                let mut variants = variants.iter();
 | 
					                let mut variants = variants.iter();
 | 
				
			||||||
                separate(", ", || {
 | 
					                separate(", ", || {
 | 
				
			||||||
                    let (name, def) = variants.next()?;
 | 
					                    let (name, def) = variants.next()?;
 | 
				
			||||||
                    Some(move |f: &mut Delimit<_>| match def {
 | 
					                    Some(move |f: &mut Delimit<_>| write!(f, "{name}: #{def}"))
 | 
				
			||||||
                        Some(def) => write!(f, "{name}: #{def}"),
 | 
					 | 
				
			||||||
                        None => write!(f, "{name}"),
 | 
					 | 
				
			||||||
                    })
 | 
					 | 
				
			||||||
                })(f.delimit_with("enum {", "}"))
 | 
					                })(f.delimit_with("enum {", "}"))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Adt::Struct(members) => {
 | 
					            Adt::Struct(members) => {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user