diff --git a/compiler/cl-typeck/examples/typeck.rs b/compiler/cl-typeck/examples/typeck.rs index 2848c3d..750981a 100644 --- a/compiler/cl-typeck/examples/typeck.rs +++ b/compiler/cl-typeck/examples/typeck.rs @@ -72,6 +72,7 @@ fn main_menu(prj: &mut Table) -> Result<(), RlError> { match line { "c" | "code" => enter_code(prj)?, "clear" => clear()?, + "dump" => dump(prj)?, "d" | "desugar" => live_desugar()?, "e" | "exit" => return Ok(Response::Break), "f" | "file" => import_files(prj)?, @@ -254,7 +255,7 @@ fn infer_all(table: &mut Table) -> Result<(), Box> { } e => eprint!("{e}"), } - eprintln!(" in {} ({id})", id.to_entry(table)) + eprintln!(" in {id}\n({})\n", id.to_entry(table).source().unwrap()) } println!("...Inferred!"); @@ -404,6 +405,30 @@ fn inline_modules(code: cl_ast::File, path: impl AsRef) -> cl_ast::F } } +fn dump(table: &Table) -> Result<(), Box> { + fn dump_recursive( + name: cl_ast::Sym, + entry: Entry, + depth: usize, + to_file: &mut std::fs::File, + ) -> std::io::Result<()> { + use std::io::Write; + write!(to_file, "{:w$}{name}: {entry}", "", w = depth)?; + if let Some(children) = entry.children() { + writeln!(to_file, " {{")?; + for (name, child) in children { + dump_recursive(*name, entry.with_id(*child), depth + 2, to_file)?; + } + write!(to_file, "{:w$}}}", "", w = depth)?; + } + writeln!(to_file) + } + + let mut file = std::fs::File::create("typeck-table.ron")?; + dump_recursive("root".into(), table.root_entry(), 0, &mut file)?; + Ok(()) +} + fn clear() -> Result<(), Box> { println!("\x1b[H\x1b[2J"); banner(); diff --git a/compiler/cl-typeck/src/entry.rs b/compiler/cl-typeck/src/entry.rs index 1f64079..658188a 100644 --- a/compiler/cl-typeck/src/entry.rs +++ b/compiler/cl-typeck/src/entry.rs @@ -20,6 +20,7 @@ use crate::{ type_kind::TypeKind, }; +mod debug; mod display; impl Handle { @@ -31,24 +32,65 @@ impl Handle { } } -#[derive(Debug)] pub struct Entry<'t, 'a> { table: &'t Table<'a>, id: Handle, } +macro_rules! impl_entry_ { + () => { + pub const fn id(&self) -> Handle { + self.id + } + + pub const fn inner(&'t self) -> &'t Table<'a> { + self.table + } + + pub fn kind(&self) -> Option<&NodeKind> { + self.table.kind(self.id) + } + + pub const fn root(&self) -> Handle { + self.table.root() + } + + pub fn children(&self) -> Option<&HashMap> { + self.table.children(self.id) + } + + pub fn imports(&self) -> Option<&HashMap> { + self.table.imports(self.id) + } + + pub fn bodies(&self) -> Option<&'a Expr> { + self.table.body(self.id) + } + + pub fn span(&self) -> Option<&Span> { + self.table.span(self.id) + } + + pub fn meta(&self) -> Option<&[Meta]> { + self.table.meta(self.id) + } + + pub fn source(&self) -> Option<&Source<'a>> { + self.table.source(self.id) + } + + pub fn name(&self) -> Option { + self.table.name(self.id) + } + }; +} + impl<'t, 'a> Entry<'t, 'a> { pub const fn new(table: &'t Table<'a>, id: Handle) -> Self { Self { table, id } } - pub const fn id(&self) -> Handle { - self.id - } - - pub fn inner(&self) -> &'t Table<'a> { - self.table - } + impl_entry_!(); pub const fn with_id(&self, id: Handle) -> Entry<'t, 'a> { Self { table: self.table, id } @@ -58,46 +100,14 @@ impl<'t, 'a> Entry<'t, 'a> { Some(Entry { id: self.table.nav(self.id, path)?, table: self.table }) } - pub const fn root(&self) -> Handle { - self.table.root() - } - - pub fn kind(&self) -> Option<&'t NodeKind> { - self.table.kind(self.id) - } - pub fn parent(&self) -> Option> { Some(Entry { id: *self.table.parent(self.id)?, ..*self }) } - pub fn children(&self) -> Option<&'t HashMap> { - self.table.children(self.id) - } - - pub fn imports(&self) -> Option<&'t HashMap> { - self.table.imports(self.id) - } - - pub fn bodies(&self) -> Option<&'a Expr> { - self.table.body(self.id) - } - pub fn ty(&self) -> Option<&'t TypeKind> { self.table.ty(self.id) } - pub fn span(&self) -> Option<&'t Span> { - self.table.span(self.id) - } - - pub fn meta(&self) -> Option<&'a [Meta]> { - self.table.meta(self.id) - } - - pub fn source(&self) -> Option<&'t Source<'a>> { - self.table.source(self.id) - } - pub fn impl_target(&self) -> Option> { Some(Entry { id: self.table.impl_target(self.id)?, ..*self }) } @@ -105,10 +115,6 @@ impl<'t, 'a> Entry<'t, 'a> { pub fn selfty(&self) -> Option> { Some(Entry { id: self.table.selfty(self.id)?, ..*self }) } - - pub fn name(&self) -> Option { - self.table.name(self.id) - } } #[derive(Debug)] @@ -122,12 +128,18 @@ impl<'t, 'a> EntryMut<'t, 'a> { Self { table, id } } - pub fn as_ref(&self) -> Entry<'_, 'a> { - Entry { table: self.table, id: self.id } + impl_entry_!(); + + pub fn ty(&self) -> Option<&TypeKind> { + self.table.ty(self.id) } - pub const fn id(&self) -> Handle { - self.id + pub fn inner_mut(&mut self) -> &mut Table<'a> { + self.table + } + + pub fn as_ref(&self) -> Entry<'_, 'a> { + Entry { table: self.table, id: self.id } } /// Evaluates a [TypeExpression] in this entry's context @@ -182,6 +194,10 @@ impl<'t, 'a> EntryMut<'t, 'a> { self.table.set_impl_target(self.id, target) } + pub fn mark_unchecked(&mut self) { + self.table.mark_unchecked(self.id) + } + pub fn mark_use_item(&mut self) { self.table.mark_use_item(self.id) } diff --git a/compiler/cl-typeck/src/entry/debug.rs b/compiler/cl-typeck/src/entry/debug.rs new file mode 100644 index 0000000..618e740 --- /dev/null +++ b/compiler/cl-typeck/src/entry/debug.rs @@ -0,0 +1,33 @@ +//! [std::fmt::Debug] implementation for [Entry] + +use super::Entry; + +impl std::fmt::Debug for Entry<'_, '_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // virtual fields + let mut ds = f.debug_struct("Entry"); + if let Some(name) = self.name() { + ds.field("name", &name.to_ref()); + } + ds.field("kind", &self.kind()); + if let Some(ty) = self.ty() { + ds.field("type", ty); + } + if let Some(meta) = self.meta() { + ds.field("meta", &meta); + } + if let Some(body) = self.bodies() { + ds.field("body", body); + } + if let Some(children) = self.children() { + ds.field("children", children); + } + if let Some(imports) = self.imports() { + ds.field("imports", imports); + } + // if let Some(source) = self.source() { + // ds.field("source", source); + // } + ds.field("implements", &self.impl_target()).finish() + } +} diff --git a/compiler/cl-typeck/src/entry/display.rs b/compiler/cl-typeck/src/entry/display.rs index 6d89d51..7915f0e 100644 --- a/compiler/cl-typeck/src/entry/display.rs +++ b/compiler/cl-typeck/src/entry/display.rs @@ -60,7 +60,14 @@ impl fmt::Display for Entry<'_, '_> { TypeKind::Module => write!(f, "module?"), } } else { - write!(f, "{kind}") + match kind { + NodeKind::Type + | NodeKind::Const + | NodeKind::Static + | NodeKind::Temporary + | NodeKind::Let => write!(f, "WARNING: NO TYPE ASSIGNED FOR {}", self.id), + _ => write!(f, "{kind}"), + } } } } diff --git a/compiler/cl-typeck/src/stage/categorize.rs b/compiler/cl-typeck/src/stage/categorize.rs index a82e75e..866a906 100644 --- a/compiler/cl-typeck/src/stage/categorize.rs +++ b/compiler/cl-typeck/src/stage/categorize.rs @@ -1,6 +1,7 @@ //! Categorizes an entry in a table according to its embedded type information - +#![allow(unused)] use crate::{ + entry::EntryMut, handle::Handle, source::Source, table::{NodeKind, Table}, @@ -11,39 +12,37 @@ use cl_ast::*; /// Ensures a type entry exists for the provided handle in the table pub fn categorize(table: &mut Table, node: Handle) -> CatResult<()> { - if let Some(meta) = table.meta(node) { - for meta @ Meta { name, kind } in meta { - if let ("lang", MetaKind::Equals(Literal::String(s))) = (&**name, kind) { - let kind = - TypeKind::Primitive(s.parse().map_err(|_| Error::BadMeta(meta.clone()))?); - table.set_ty(node, kind); - return Ok(()); - } - } - } - let Some(source) = table.source(node) else { return Ok(()); }; match source { - Source::Root => Ok(()), - Source::Module(_) => Ok(()), - Source::Alias(a) => cat_alias(table, node, a), - Source::Enum(e) => cat_enum(table, node, e), - 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), - Source::Function(f) => cat_function(table, node, f), - Source::Local(l) => cat_local(table, node, l), - Source::Impl(i) => cat_impl(table, node, i), - Source::Use(_) => Ok(()), - Source::Ty(ty) => ty - .evaluate(table, node) - .map_err(|e| Error::TypeEval(e, " while categorizing a type")) - .map(drop), + Source::Alias(a) => cat_alias(table, node, a)?, + Source::Enum(e) => cat_enum(table, node, e)?, + 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)?, + Source::Function(f) => cat_function(table, node, f)?, + Source::Local(l) => cat_local(table, node, l)?, + Source::Impl(i) => cat_impl(table, node, i)?, + _ => {} } + + if let Some(meta) = table.meta(node) { + for meta @ Meta { name, kind } in meta { + if let ("lang", MetaKind::Equals(Literal::String(s))) = (&**name, kind) { + if let Ok(prim) = s.parse() { + table.set_ty(node, TypeKind::Primitive(prim)); + } else { + table.mark_lang_item(s.into(), node); + continue; + } + return Ok(()); + } + } + } + Ok(()) } fn parent(table: &Table, node: Handle) -> Handle { @@ -108,7 +107,6 @@ fn cat_enum<'a>(_table: &mut Table<'a>, _node: Handle, e: &'a Enum) -> CatResult fn cat_variant<'a>(table: &mut Table<'a>, node: Handle, v: &'a Variant) -> CatResult<()> { let Variant { name, kind, body } = v; let parent = table.parent(node).copied().unwrap_or(table.root()); - table.add_child(parent, *name, node); match (kind, body) { (StructKind::Empty, None) => { table.set_ty(node, TypeKind::Adt(Adt::UnitStruct)); @@ -195,7 +193,7 @@ fn cat_local(table: &mut Table, node: Handle, l: &Let) -> CatResult<()> { fn cat_impl(table: &mut Table, node: Handle, i: &Impl) -> CatResult<()> { let parent = parent(table, node); - let Impl { target, body: _ } = i; + let Impl { gens, target, body: _ } = i; let target = match target { ImplKind::Type(t) => t.evaluate(table, parent), ImplKind::Trait { impl_trait: _, for_type: t } => t.evaluate(table, parent), diff --git a/compiler/cl-typeck/src/stage/implement.rs b/compiler/cl-typeck/src/stage/implement.rs index d94be5f..e8cb6aa 100644 --- a/compiler/cl-typeck/src/stage/implement.rs +++ b/compiler/cl-typeck/src/stage/implement.rs @@ -15,9 +15,9 @@ pub fn impl_one(table: &mut Table, node: Handle) -> Result<(), Handle> { let Some(target) = table.impl_target(node) else { Err(node)? }; - let Table { children, imports, .. } = table; - if let Some(children) = children.get(&node) { - imports.entry(target).or_default().extend(children); + if let Some(children) = table.children.get_mut(&node) { + let children = children.clone(); + table.children.entry(target).or_default().extend(children); } Ok(()) } diff --git a/compiler/cl-typeck/src/stage/infer/engine.rs b/compiler/cl-typeck/src/stage/infer/engine.rs index 8a2194a..cdf7257 100644 --- a/compiler/cl-typeck/src/stage/infer/engine.rs +++ b/compiler/cl-typeck/src/stage/infer/engine.rs @@ -1,7 +1,10 @@ +use std::{cell::Cell, collections::HashSet, rc::Rc}; + use super::error::InferenceError; use crate::{ entry::Entry, handle::Handle, + source::Source, stage::infer::inference::Inference, table::{NodeKind, Table}, type_expression::TypeExpression, @@ -28,14 +31,16 @@ use cl_ast::Sym; - for type T -> R // on a per-case basis! */ +type HandleSet = Rc>>; + pub struct InferenceEngine<'table, 'a> { pub(super) table: &'table mut Table<'a>, /// The current working node pub(crate) at: Handle, /// The current breakset - pub(crate) bset: Handle, + pub(crate) bset: HandleSet, /// The current returnset - pub(crate) rset: Handle, + pub(crate) rset: HandleSet, } impl<'table, 'a> InferenceEngine<'table, 'a> { @@ -46,48 +51,69 @@ impl<'table, 'a> InferenceEngine<'table, 'a> { /// Constructs a new [`InferenceEngine`], scoped around a [`Handle`] in a [`Table`]. pub fn new(table: &'table mut Table<'a>, at: Handle) -> Self { - let never = table.anon_type(TypeKind::Never); - Self { at, table, bset: never, rset: never } + Self { at, table, bset: Default::default(), rset: Default::default() } } /// Constructs an [`InferenceEngine`] that borrows the same table as `self`, /// but with a shortened lifetime. pub fn scoped(&mut self) -> InferenceEngine<'_, 'a> { - InferenceEngine { at: self.at, table: self.table, bset: self.bset, rset: self.rset } + InferenceEngine { + at: self.at, + table: self.table, + bset: self.bset.clone(), + rset: self.rset.clone(), + } } pub fn infer_all(&mut self) -> Vec<(Handle, InferenceError)> { - let iter = self.table.handle_iter(); + let queue = std::mem::take(&mut self.table.unchecked); let mut res = Vec::new(); - for handle in iter { + for handle in queue { let mut eng = self.at(handle); - // TODO: use sources instead of bodies, and infer the type globally - let Some(body) = eng.table.body(handle) else { + let Some(source) = eng.table.source(handle) else { + eprintln!("No source found for {handle}"); continue; }; - eprintln!("Evaluating body {body}"); - match body.infer(&mut eng) { - Ok(ty) => println!("=> {}", eng.table.entry(ty)), - Err(e) => { - match &e { - &InferenceError::Mismatch(a, b) => { - eprintln!( - "=> Mismatched types: {}, {}", - eng.table.entry(a), - eng.table.entry(b) - ); - } - &InferenceError::Recursive(a, b) => { - eprintln!( - "=> Recursive types: {}, {}", - eng.table.entry(a), - eng.table.entry(b) - ); - } - e => eprintln!("=> {e}"), - } - res.push((handle, e)) + + println!("Inferring {source}"); + + let ret = match source { + Source::Module(v) => v.infer(&mut eng), + Source::Alias(v) => v.infer(&mut eng), + Source::Enum(v) => v.infer(&mut eng), + Source::Variant(v) => v.infer(&mut eng), + Source::Struct(v) => v.infer(&mut eng), + Source::Const(v) => v.infer(&mut eng), + Source::Static(v) => v.infer(&mut eng), + Source::Function(v) => v.infer(&mut eng), + Source::Local(v) => v.infer(&mut eng), + Source::Impl(v) => v.infer(&mut eng), + _ => Ok(eng.empty()), + }; + + match &ret { + &Ok(handle) => println!("=> {}", eng.entry(handle)), + Err(err @ InferenceError::AnnotationEval(_)) => eprintln!("=> ERROR: {err}"), + Err(InferenceError::FieldCount(h, want, got)) => { + eprintln!("=> ERROR: Field count {want} != {got} in {}", eng.entry(*h)) } + Err(err @ InferenceError::NotFound(_)) => eprintln!("=> ERROR: {err}"), + Err(InferenceError::Mismatch(h1, h2)) => eprintln!( + "=> ERROR: Type mismatch {} != {}", + eng.entry(*h1), + eng.entry(*h2) + ), + Err(InferenceError::Recursive(h1, h2)) => eprintln!( + "=> ERROR: Cycle found in types {}, {}", + eng.entry(*h1), + eng.entry(*h2) + ), + } + println!(); + + if let Err(err) = ret { + res.push((handle, err)); + eng.table.mark_unchecked(handle); } } res @@ -99,11 +125,31 @@ impl<'table, 'a> InferenceEngine<'table, 'a> { } pub fn open_bset(&mut self) -> InferenceEngine<'_, 'a> { - InferenceEngine { bset: self.new_var(), ..self.scoped() } + InferenceEngine { bset: Default::default(), ..self.scoped() } } pub fn open_rset(&mut self) -> InferenceEngine<'_, 'a> { - InferenceEngine { rset: self.new_var(), ..self.scoped() } + InferenceEngine { rset: Default::default(), ..self.scoped() } + } + + pub fn bset(&mut self, ty: Handle) -> Result<(), InferenceError> { + match self.bset.get() { + Some(bset) => self.unify(ty, bset), + None => { + self.bset.set(Some(ty)); + Ok(()) + } + } + } + + pub fn rset(&mut self, ty: Handle) -> Result<(), InferenceError> { + match self.rset.get() { + Some(rset) => self.unify(ty, rset), + None => { + self.rset.set(Some(ty)); + Ok(()) + } + } } /// Constructs an [Entry] out of a [Handle], for ease of use @@ -111,12 +157,6 @@ impl<'table, 'a> InferenceEngine<'table, 'a> { self.table.entry(of) } - #[deprecated = "Use dedicated methods instead."] - pub fn from_type_kind(&mut self, kind: TypeKind) -> Handle { - // TODO: preserve type heirarchy (for, i.e., reference types) - self.table.anon_type(kind) - } - pub fn by_name>( &mut self, name: &N, @@ -129,6 +169,10 @@ impl<'table, 'a> InferenceEngine<'table, 'a> { self.table.type_variable() } + pub fn new_inferred(&mut self) -> Handle { + self.table.inferred_type() + } + /// Creates a variable that is a new instance of another [Type](Handle) pub fn new_inst(&mut self, of: Handle) -> Handle { self.table.anon_type(TypeKind::Instance(of)) @@ -217,7 +261,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> { /// Creates a new inferred-integer literal pub fn integer_literal(&mut self) -> Handle { - let h = self.table.new_entry(self.at, NodeKind::Local); + let h = self.table.new_entry(self.at, NodeKind::Temporary); self.table .set_ty(h, TypeKind::Primitive(Primitive::Integer)); h @@ -225,20 +269,22 @@ impl<'table, 'a> InferenceEngine<'table, 'a> { /// Creates a new inferred-float literal pub fn float_literal(&mut self) -> Handle { - let h = self.table.new_entry(self.at, NodeKind::Local); + let h = self.table.new_entry(self.at, NodeKind::Temporary); self.table.set_ty(h, TypeKind::Primitive(Primitive::Float)); h } /// Enters a new scope - pub fn local_scope(&mut self) { - let scope = self.table.new_entry(self.at, NodeKind::Local); + pub fn local_scope(&mut self, name: Sym) { + let scope = self.table.new_entry(self.at, NodeKind::Scope); + self.table.add_child(self.at, name, scope); self.at = scope; } /// Creates a new locally-scoped InferenceEngine. pub fn block_scope(&mut self) -> InferenceEngine<'_, 'a> { - let scope = self.table.new_entry(self.at, NodeKind::Local); + let scope = self.table.new_entry(self.at, NodeKind::Scope); + self.table.add_child(self.at, "".into(), scope); self.at(scope) } @@ -264,27 +310,44 @@ impl<'table, 'a> InferenceEngine<'table, 'a> { /// Checks whether there are any unbound type variables in this type pub fn is_generic(&self, ty: Handle) -> bool { - let entry = self.table.entry(ty); - let Some(ty) = entry.ty() else { - return false; - }; - match ty { - TypeKind::Inferred => false, - TypeKind::Variable => true, - &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)| 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, - TypeKind::Adt(Adt::Union(tys)) => tys.iter().any(|&(_, ty)| self.is_generic(ty)), - &TypeKind::Ref(h) => self.is_generic(h), - &TypeKind::Slice(h) => self.is_generic(h), - TypeKind::Tuple(handles) => handles.iter().any(|&ty| self.is_generic(ty)), - &TypeKind::FnSig { args, rety } => self.is_generic(args) || self.is_generic(rety), - TypeKind::Empty | TypeKind::Never | TypeKind::Module => false, + fn is_generic_rec(this: &InferenceEngine, ty: Handle, seen: &mut HashSet) -> bool { + if !seen.insert(ty) { + return false; + } + let entry = this.table.entry(ty); + let Some(ty) = entry.ty() else { + return false; + }; + match ty { + TypeKind::Inferred => false, + TypeKind::Variable => true, + &TypeKind::Array(ty, _) => is_generic_rec(this, ty, seen), + &TypeKind::Instance(ty) => is_generic_rec(this, ty, seen), + TypeKind::Primitive(_) => false, + TypeKind::Adt(Adt::Enum(tys)) => { + tys.iter().any(|&(_, ty)| is_generic_rec(this, ty, seen)) + } + TypeKind::Adt(Adt::Struct(tys)) => { + tys.iter().any(|&(_, _, ty)| is_generic_rec(this, ty, seen)) + } + TypeKind::Adt(Adt::TupleStruct(tys)) => { + tys.iter().any(|&(_, ty)| is_generic_rec(this, ty, seen)) + } + TypeKind::Adt(Adt::UnitStruct) => false, + TypeKind::Adt(Adt::Union(tys)) => { + tys.iter().any(|&(_, ty)| is_generic_rec(this, ty, seen)) + } + &TypeKind::Ref(ty) => is_generic_rec(this, ty, seen), + &TypeKind::Ptr(ty) => is_generic_rec(this, ty, seen), + &TypeKind::Slice(ty) => is_generic_rec(this, ty, seen), + TypeKind::Tuple(tys) => tys.iter().any(|&ty| is_generic_rec(this, ty, seen)), + &TypeKind::FnSig { args, rety } => { + is_generic_rec(this, args, seen) || is_generic_rec(this, rety, seen) + } + TypeKind::Empty | TypeKind::Never | TypeKind::Module => false, + } } + is_generic_rec(self, ty, &mut HashSet::new()) } /// Makes a deep copy of a type expression. @@ -298,8 +361,10 @@ impl<'table, 'a> InferenceEngine<'table, 'a> { let Some(ty) = entry.ty().cloned() else { return ty; }; + + // TODO: Parent the deep clone into a new "monomorphs" branch of tree match ty { - TypeKind::Variable => self.new_var(), + TypeKind::Variable => self.new_inferred(), TypeKind::Array(h, s) => { let ty = self.deep_clone(h); self.table.anon_type(TypeKind::Array(ty, s)) @@ -396,6 +461,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> { items.iter().any(|(_, other)| self.occurs_in(this, *other)) } TypeKind::Ref(other) => self.occurs_in(this, *other), + TypeKind::Ptr(other) => self.occurs_in(this, *other), TypeKind::Slice(other) => self.occurs_in(this, *other), TypeKind::Array(other, _) => self.occurs_in(this, *other), TypeKind::Tuple(handles) => handles.iter().any(|&other| self.occurs_in(this, other)), @@ -415,6 +481,9 @@ impl<'table, 'a> InferenceEngine<'table, 'a> { /// Unifies two types pub fn unify(&mut self, this: Handle, other: Handle) -> Result<(), InferenceError> { let (ah, bh) = (self.prune(this), self.prune(other)); + if ah == bh { + return Ok(()); + } let (a, b) = (self.table.entry(ah), self.table.entry(bh)); let (Some(a), Some(b)) = (a.ty(), b.ty()) else { return Err(InferenceError::Mismatch(ah, bh)); @@ -427,10 +496,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> { } (_, TypeKind::Inferred) => self.unify(bh, ah), - (TypeKind::Variable, _) => { - self.set_instance(ah, bh); - Ok(()) - } + (TypeKind::Variable, _) => Err(InferenceError::Mismatch(ah, bh)), (TypeKind::Instance(a), TypeKind::Instance(b)) if !self.occurs_in(*a, *b) => { self.set_instance(*a, *b); Ok(()) @@ -467,6 +533,26 @@ impl<'table, 'a> InferenceEngine<'table, 'a> { } Ok(()) } + (TypeKind::Adt(Adt::Enum(en)), TypeKind::Adt(_)) => { + #[allow(unused)] + let Some(other_parent) = self.table.parent(bh) else { + Err(InferenceError::Mismatch(ah, bh))? + }; + + if ah != *other_parent { + Err(InferenceError::Mismatch(ah, *other_parent))? + } + + #[allow(unused)] + for (sym, handle) in en { + let handle = self.def_usage(*handle); + if handle == bh { + return Ok(()); + } + } + + Err(InferenceError::Mismatch(ah, bh)) + } (TypeKind::Adt(Adt::Struct(ia)), TypeKind::Adt(Adt::Struct(ib))) if ia.len() == ib.len() => { diff --git a/compiler/cl-typeck/src/stage/infer/error.rs b/compiler/cl-typeck/src/stage/infer/error.rs index 8a996b1..4ae9fd9 100644 --- a/compiler/cl-typeck/src/stage/infer/error.rs +++ b/compiler/cl-typeck/src/stage/infer/error.rs @@ -31,3 +31,9 @@ impl fmt::Display for InferenceError { } } } + +impl From for InferenceError { + fn from(value: crate::type_expression::Error) -> Self { + Self::AnnotationEval(value) + } +} diff --git a/compiler/cl-typeck/src/stage/infer/inference.rs b/compiler/cl-typeck/src/stage/infer/inference.rs index 058747f..10be487 100644 --- a/compiler/cl-typeck/src/stage/infer/inference.rs +++ b/compiler/cl-typeck/src/stage/infer/inference.rs @@ -7,7 +7,6 @@ use std::iter; use super::{engine::InferenceEngine, error::InferenceError}; use crate::{ handle::Handle, - table::NodeKind, type_expression::TypeExpression, type_kind::{Adt, TypeKind}, }; @@ -22,9 +21,227 @@ pub trait Inference<'a> { fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult; } +impl<'a> Inference<'a> for File { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + let Self { name: _, items } = self; + for item in items { + item.infer(e)?; + } + Ok(e.empty()) + } +} + +impl<'a> Inference<'a> for Item { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + let Self { span: _, attrs: _, vis: _, kind } = self; + kind.infer(e) + } +} + +impl<'a> Inference<'a> for ItemKind { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + match self { + ItemKind::Module(v) => v.infer(e), + ItemKind::Alias(v) => v.infer(e), + ItemKind::Enum(v) => v.infer(e), + ItemKind::Struct(v) => v.infer(e), + ItemKind::Const(v) => v.infer(e), + ItemKind::Static(v) => v.infer(e), + ItemKind::Function(v) => v.infer(e), + ItemKind::Impl(v) => v.infer(e), + ItemKind::Use(_v) => Ok(e.empty()), + } + } +} + +impl<'a> Inference<'a> for Generics { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + // bind names + for name in &self.vars { + let ty = e.new_var(); + e.table.add_child(e.at, *name, ty); + } + Ok(e.empty()) + } +} + +impl<'a> Inference<'a> for Module { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + let Self { name, file } = self; + let Some(file) = file else { + return Err(InferenceError::NotFound((*name).into())); + }; + let module = e.by_name(name)?; + e.at(module).infer(file) + } +} + +impl<'a> Inference<'a> for Alias { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + Ok(e.empty()) + } +} + +impl<'a> Inference<'a> for Const { + #[allow(unused)] + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + let Self { name, ty, init } = self; + // Same as static + let node = e.by_name(name)?; + let ty = e.infer(ty)?; + let mut scope = e.at(node); + // infer body + let body = scope.infer(init)?; + // unify with ty + e.unify(body, ty)?; + + Ok(node) + } +} + +impl<'a> Inference<'a> for Static { + #[allow(unused)] + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + let Static { mutable, name, ty, init } = self; + let node = e.by_name(name)?; + let ty = e.infer(ty)?; + let mut scope = e.at(node); + // infer body + let body = scope.infer(init)?; + // unify with ty + e.unify(body, ty)?; + + Ok(node) + } +} + +impl<'a> Inference<'a> for Function { + #[allow(unused)] + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + let Self { name, gens, sign, bind, body } = self; + // bind name to signature + let node = e.by_name(name)?; + let node = e.deep_clone(node); + let fnty = e.by_name(sign)?; + e.unify(node, fnty)?; + + // bind gens to new variables at function scope + let mut scope = e.at(node); + scope.infer(gens)?; + + // bind binds to args + let pat = scope.infer(bind)?; + let arg = scope.by_name(sign.args.as_ref())?; + scope.unify(pat, arg); + + let mut retscope = scope.open_rset(); + + // infer body + let bodty = retscope.infer(body)?; + let rety = sign.rety.infer(&mut retscope)?; + // unify body with rety + retscope.unify(bodty, rety)?; + // unify rset with rety + if let Some(rset) = retscope.rset.get() { + scope.unify(rset, rety)?; + } + Ok(node) + } +} + +// TODO: do we need type inference/checking in struct definitions? +// there are no bodies + +impl<'a> Inference<'a> for Enum { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + let Self { name, gens, variants } = self; + let node = e.by_name(name)?; + let mut scope = e.at(node); + + scope.infer(gens)?; + for variant in variants { + let var_ty = scope.infer(variant)?; + scope.unify(var_ty, node)?; + } + Ok(node) + } +} + +impl<'a> Inference<'a> for Variant { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + let Self { name: _, kind: _, body } = self; + let ty = e.new_inferred(); + + // TODO: evaluate kind + + if let Some(body) = body { + let value = body.infer(e)?; + e.unify(ty, value)?; + } + + Ok(ty) + } +} + +impl<'a> Inference<'a> for Struct { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + Ok(e.new_inferred()) + } +} + +impl<'a> Inference<'a> for Impl { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + let Self { gens: _, target, body } = self; + // TODO: match gens to target gens + // gens.infer(e)?; + let instance = target.infer(e)?; + let instance = e.def_usage(instance); + let mut scope = e.at(instance); + scope.infer(body) + } +} + +impl<'a> Inference<'a> for ImplKind { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + match self { + ImplKind::Type(ty) => ty.infer(e), + ImplKind::Trait { impl_trait: _, for_type } => for_type.infer(e), + } + } +} + +impl<'a> Inference<'a> for Ty { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + Ok(e.by_name(self)?) + } +} + +impl<'a> Inference<'a> for cl_ast::Stmt { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + let Self { span: _, kind, semi } = self; + let out = kind.infer(e)?; + Ok(match semi { + Semi::Terminated => e.empty(), + Semi::Unterminated => out, + }) + } +} + +impl<'a> Inference<'a> for cl_ast::StmtKind { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + match self { + StmtKind::Empty => Ok(e.empty()), + StmtKind::Item(item) => item.infer(e), + StmtKind::Expr(expr) => expr.infer(e), + } + } +} + impl<'a> Inference<'a> for cl_ast::Expr { fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { - self.kind.infer(e) + let out = self.kind.infer(e)?; + println!("expr ({self}) -> {}", e.entry(out)); + Ok(out) } } @@ -32,7 +249,7 @@ impl<'a> Inference<'a> for cl_ast::ExprKind { fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { match self { ExprKind::Empty => Ok(e.empty()), - ExprKind::Closure(_) => todo!("Infer the type of a closure"), + ExprKind::Closure(closure) => closure.infer(e), ExprKind::Tuple(tuple) => tuple.infer(e), ExprKind::Structor(structor) => structor.infer(e), ExprKind::Array(array) => array.infer(e), @@ -65,6 +282,23 @@ impl<'a> Inference<'a> for cl_ast::ExprKind { } } +impl<'a> Inference<'a> for Closure { + fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { + let Self { arg, body } = self; + let args = arg.infer(e)?; + + let mut scope = e.block_scope(); + let mut scope = scope.open_rset(); + let rety = scope.infer(body)?; + + if let Some(rset) = scope.rset.get() { + e.unify(rety, rset)?; + } + + Ok(e.table.anon_type(TypeKind::FnSig { args, rety })) + } +} + impl<'a> Inference<'a> for Tuple { fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { let Tuple { exprs } = self; @@ -123,7 +357,7 @@ impl<'a> Inference<'a> for Structor { impl<'a> Inference<'a> for Array { fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { let Array { values } = self; - let out = e.new_var(); + let out = e.new_inferred(); for value in values { let ty = value.infer(e)?; e.unify(out, ty)?; @@ -136,7 +370,15 @@ impl<'a> Inference<'a> for ArrayRep { fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult { let ArrayRep { value, repeat } = self; let ty = value.infer(e)?; - Ok(e.new_array(ty, *repeat)) + let rep = repeat.infer(e)?; + let usize_ty = e.usize(); + e.unify(rep, usize_ty)?; + match &repeat.kind { + ExprKind::Literal(Literal::Int(repeat)) => Ok(e.new_array(ty, *repeat as usize)), + _ => { + todo!("TODO: constant folding before type checking?"); + } + } } } @@ -196,14 +438,13 @@ impl<'a> Inference<'a> for Block { _ => {} } } - match (&ret.kind, &ret.semi) { - (StmtKind::Expr(expr), Semi::Terminated) => { - expr.infer(&mut e)?; - } - (StmtKind::Expr(expr), Semi::Unterminated) => { - return expr.infer(&mut e); - } - _ => {} + let out = if let StmtKind::Expr(expr) = &ret.kind { + expr.infer(&mut e)? + } else { + empty + }; + if Semi::Unterminated == ret.semi { + return Ok(out); } } Ok(empty) @@ -315,10 +556,11 @@ impl<'a> Inference<'a> for Unary { match kind { UnaryKind::Deref => { let tail = tail.infer(e)?; + let tail = e.def_usage(tail); // TODO: get the base type match e.entry(tail).ty() { Some(&TypeKind::Ref(h)) => Ok(h), - other => todo!("Deref {other:?}"), + _ => todo!("Deref {}", e.entry(tail)), } } UnaryKind::Loop => { @@ -333,7 +575,10 @@ impl<'a> Inference<'a> for Unary { e.unify(tail, empt)?; // Return breakset - Ok(e.bset) + match e.bset.get() { + Some(bset) => Ok(bset), + None => Ok(e.never()), + } } _op => { // Infer the tail expression @@ -455,7 +700,7 @@ impl<'a> Inference<'a> for Let { Some(ty) => ty .evaluate(e.table, e.at) .map_err(InferenceError::AnnotationEval)?, - None => e.new_var(), + None => e.new_inferred(), }; // Infer the initializer if let Some(init) = init { @@ -465,8 +710,6 @@ impl<'a> Inference<'a> for Let { } // Deep copy the ty, if it exists let ty = e.deep_clone(ty); - // Enter a local scope (modifies the current scope) - e.local_scope(); // Infer the pattern let patty = name.infer(e)?; // Unify the pattern and the ty @@ -513,11 +756,9 @@ impl<'a> Inference<'a> for Pattern { Pattern::Name(name) => { // Evaluating a pattern creates and enters a new scope. // Surely this will cause zero problems. - let node = e.table.new_entry(e.at, NodeKind::Local); - e.table.set_ty(node, TypeKind::Variable); - e.table.add_child(e.at, *name, node); - e.at = node; - Ok(node) + e.local_scope(*name); + e.table.set_ty(e.at, TypeKind::Inferred); + Ok(e.at) } Pattern::Path(path) => { // Evaluating a path pattern puts type constraints on the scrutinee @@ -525,8 +766,12 @@ impl<'a> Inference<'a> for Pattern { .map_err(|_| InferenceError::NotFound(path.clone())) } Pattern::Literal(literal) => literal.infer(e), - Pattern::Rest(Some(pat)) => pat.infer(e), // <-- glaring soundness holes - Pattern::Rest(_) => todo!("Fix glaring soundness holes in pattern"), + Pattern::Rest(Some(pat)) => { + eprintln!("TODO: Rest patterns in tuples?"); + let ty = pat.infer(e)?; + Ok(e.new_slice(ty)) + } + Pattern::Rest(_) => Ok(e.new_inferred()), Pattern::Ref(_, pattern) => { let ty = pattern.infer(e)?; Ok(e.new_ref(ty)) @@ -561,12 +806,30 @@ impl<'a> Inference<'a> for Pattern { Ok(e.new_slice(ty)) } [] => { - let ty = e.new_var(); + let ty = e.new_inferred(); Ok(e.new_slice(ty)) } }, - Pattern::Struct(_path, _items) => todo!("Struct patterns"), - Pattern::TupleStruct(_path, _patterns) => todo!("Tuple struct patterns"), + Pattern::Struct(_path, _items) => { + eprintln!("TODO: struct patterns: {self}"); + Ok(e.empty()) + } + Pattern::TupleStruct(path, patterns) => { + eprintln!("TODO: tuple struct patterns: {self}"); + let struc = e.by_name(path)?; + let Some(TypeKind::Adt(Adt::TupleStruct(ts))) = e.entry(struc).ty() else { + Err(InferenceError::Mismatch(struc, e.never()))? + }; + let ts: Vec<_> = ts.iter().map(|(_v, h)| *h).collect(); + let tys = patterns + .iter() + .map(|pat| pat.infer(e)) + .collect::, InferenceError>>()?; + let ts = e.new_tuple(ts); + let tup = e.new_tuple(tys); + e.unify(ts, tup)?; + Ok(struc) + } } } } @@ -583,7 +846,7 @@ impl<'a> Inference<'a> for While { // Infer the fail branch let fail = fail.infer(e)?; // Unify the fail branch with breakset - let mut e = InferenceEngine { bset: fail, ..e.scoped() }; + let mut e = e.open_bset(); // Infer the pass branch let pass = pass.infer(&mut e)?; @@ -591,8 +854,13 @@ impl<'a> Inference<'a> for While { let empt = e.empty(); e.unify(pass, empt)?; - // Return breakset - Ok(e.bset) + match e.bset.get() { + None => Ok(e.empty()), + Some(bset) => { + e.unify(fail, bset)?; + Ok(fail) + } + } } } @@ -638,9 +906,8 @@ impl<'a> Inference<'a> for For { // Infer the fail branch let fail = fail.infer(&mut e)?; - // Unify the fail branch with breakset - let mut e = InferenceEngine { bset: fail, ..e.scoped() }; - e.bset = fail; + // Open a breakset + let mut e = e.open_bset(); // Infer the pass branch let pass = pass.infer(&mut e)?; @@ -649,7 +916,12 @@ impl<'a> Inference<'a> for For { e.unify(pass, empt)?; // Return breakset - Ok(e.bset) + if let Some(bset) = e.bset.get() { + e.unify(fail, bset)?; + Ok(fail) + } else { + Ok(e.empty()) + } } } @@ -665,7 +937,7 @@ impl<'a> Inference<'a> for Break { // Infer the body of the break let ty = body.infer(e)?; // Unify it with the breakset of the loop - e.unify(ty, e.bset)?; + e.bset(ty)?; // Return never Ok(e.never()) } @@ -677,7 +949,7 @@ impl<'a> Inference<'a> for Return { // Infer the body of the return let ty = body.infer(e)?; // Unify it with the return-set of the function - e.unify(ty, e.rset)?; + e.rset(ty)?; // Return never Ok(e.never()) } diff --git a/compiler/cl-typeck/src/stage/populate.rs b/compiler/cl-typeck/src/stage/populate.rs index 3d5cdf9..ed06674 100644 --- a/compiler/cl-typeck/src/stage/populate.rs +++ b/compiler/cl-typeck/src/stage/populate.rs @@ -94,27 +94,16 @@ impl<'a> Visit<'a> for Populator<'_, 'a> { } fn visit_static(&mut self, s: &'a cl_ast::Static) { - let cl_ast::Static { mutable, name, ty, init } = s; + let cl_ast::Static { name, init, .. } = s; self.inner.set_source(Source::Static(s)); self.inner.set_body(init); self.set_name(*name); - self.visit(mutable); - self.visit(ty); - self.visit(init); - } - - fn visit_module(&mut self, m: &'a cl_ast::Module) { - let cl_ast::Module { name, file } = m; - self.inner.set_source(Source::Module(m)); - self.set_name(*name); - - self.visit(file); + s.children(self); } fn visit_function(&mut self, f: &'a cl_ast::Function) { let cl_ast::Function { name, gens, sign, bind, body } = f; - // TODO: populate generics? self.inner.set_source(Source::Function(f)); self.set_name(*name); @@ -128,6 +117,14 @@ impl<'a> Visit<'a> for Populator<'_, 'a> { } } + fn visit_module(&mut self, m: &'a cl_ast::Module) { + let cl_ast::Module { name, file } = m; + self.inner.set_source(Source::Module(m)); + self.set_name(*name); + + self.visit(file); + } + fn visit_struct(&mut self, s: &'a cl_ast::Struct) { let cl_ast::Struct { name, gens, kind } = s; self.inner.set_source(Source::Struct(s)); @@ -143,12 +140,14 @@ impl<'a> Visit<'a> for Populator<'_, 'a> { self.set_name(*name); self.visit(gens); - self.visit(variants); let mut children = Vec::new(); for variant in variants.iter() { let mut entry = self.new_entry(NodeKind::Type); variant.visit_in(&mut entry); - children.push((variant.name, entry.inner.id())); + let child = entry.inner.id(); + children.push((variant.name, child)); + + self.inner.add_child(variant.name, child); } self.inner .set_ty(TypeKind::Adt(crate::type_kind::Adt::Enum(children))); @@ -156,23 +155,27 @@ impl<'a> Visit<'a> for Populator<'_, 'a> { fn visit_variant(&mut self, value: &'a cl_ast::Variant) { let cl_ast::Variant { name, kind, body } = value; - let mut entry = self.new_entry(NodeKind::Type); - entry.inner.set_source(Source::Variant(value)); - entry.visit(kind); + self.inner.set_source(Source::Variant(value)); + self.set_name(*name); + self.visit(kind); if let Some(body) = body { - entry.inner.set_body(body); + self.inner.set_body(body); } - - let child = entry.inner.id(); - self.inner.add_child(*name, child); } fn visit_impl(&mut self, i: &'a cl_ast::Impl) { - let cl_ast::Impl { target, body } = i; + let cl_ast::Impl { gens, target: _, body } = i; self.inner.set_source(Source::Impl(i)); self.inner.mark_impl_item(); - self.visit(target); + // We don't know if target is generic yet -- that's checked later. + for generic in &gens.vars { + let mut entry = self.new_entry(NodeKind::Type); + entry.inner.set_ty(TypeKind::Inferred); + + let child = entry.inner.id(); + self.inner.add_child(*generic, child); + } self.visit(body); } diff --git a/compiler/cl-typeck/src/table.rs b/compiler/cl-typeck/src/table.rs index f70ff41..707d676 100644 --- a/compiler/cl-typeck/src/table.rs +++ b/compiler/cl-typeck/src/table.rs @@ -57,8 +57,10 @@ pub struct Table<'a> { sources: HashMap>, impl_targets: HashMap, anon_types: HashMap, + lang_items: HashMap, // --- Queues for algorithms --- + pub(crate) unchecked: Vec, pub(crate) impls: Vec, pub(crate) uses: Vec, } @@ -84,6 +86,8 @@ impl<'a> Table<'a> { sources: HashMap::new(), impl_targets: HashMap::new(), anon_types: HashMap::new(), + lang_items: HashMap::new(), + unchecked: Vec::new(), impls: Vec::new(), uses: Vec::new(), } @@ -111,6 +115,10 @@ impl<'a> Table<'a> { self.imports.entry(parent).or_default().insert(name, import) } + pub fn mark_unchecked(&mut self, item: Handle) { + self.unchecked.push(item); + } + pub fn mark_use_item(&mut self, item: Handle) { let parent = self.parents[item]; self.use_items.entry(parent).or_default().push(item); @@ -121,6 +129,10 @@ impl<'a> Table<'a> { self.impls.push(item); } + pub fn mark_lang_item(&mut self, name: Sym, item: Handle) { + self.lang_items.insert(name, item); + } + pub fn handle_iter(&self) -> impl Iterator + use<> { self.kinds.keys() } @@ -209,7 +221,12 @@ impl<'a> Table<'a> { self.impl_targets.get(&node).copied() } + pub fn reparent(&mut self, node: Handle, parent: Handle) -> Handle { + self.parents.replace(node, parent) + } + pub fn set_body(&mut self, node: Handle, body: &'a Expr) -> Option<&'a Expr> { + self.mark_unchecked(node); self.bodies.insert(node, body) } @@ -311,7 +328,8 @@ pub enum NodeKind { Static, Function, Temporary, - Local, + Let, + Scope, Impl, Use, } @@ -329,7 +347,8 @@ mod display { NodeKind::Static => write!(f, "static"), NodeKind::Function => write!(f, "fn"), NodeKind::Temporary => write!(f, "temp"), - NodeKind::Local => write!(f, "local"), + NodeKind::Let => write!(f, "let"), + NodeKind::Scope => write!(f, "scope"), NodeKind::Use => write!(f, "use"), NodeKind::Impl => write!(f, "impl"), }