cl-typeck: Early type inference for let

This commit is contained in:
John 2025-04-21 04:52:59 -04:00
parent 65b75f95ce
commit 3b96833fcb
3 changed files with 51 additions and 16 deletions

View File

@ -264,12 +264,17 @@ pub mod typed_interner {
/// A [TypedInterner] hands out [Interned] references for arbitrary types.
///
/// See the [module-level documentation](self) for more information.
#[derive(Default)]
pub struct TypedInterner<'a, T: Eq + Hash> {
arena: TypedArena<'a, T>,
keys: RwLock<HashSet<&'a T>>,
}
impl<'a, T: Eq + Hash> Default for TypedInterner<'a, T> {
fn default() -> Self {
Self { arena: Default::default(), keys: Default::default() }
}
}
impl<'a, T: Eq + Hash> TypedInterner<'a, T> {
/// Creates a new [TypedInterner] backed by the provided [TypedArena]
pub fn new(arena: TypedArena<'a, T>) -> Self {

View File

@ -13,7 +13,7 @@ pub mod inference {
use std::iter;
use super::{engine::InferenceEngine, error::InferenceError};
use crate::{handle::Handle, type_kind::TypeKind};
use crate::{handle::Handle, type_expression::TypeExpression, type_kind::TypeKind};
use cl_ast::*;
pub trait Inference<'a> {
@ -33,12 +33,28 @@ pub mod inference {
ExprKind::Empty => Ok(e.from_type_kind(TypeKind::Empty)),
ExprKind::Quote(quote) => todo!("Quote: {quote}"),
ExprKind::Let(l) => {
let Let { mutable: _, name, ty, init } = l;
// Infer the pattern
let patty = name.infer(e)?;
// Deep copy the ty, if it exists
let ty = match ty {
Some(ty) => {
let ty = ty
.evaluate(e.table, e.at)
.map_err(InferenceError::AnnotationEval)?;
e.deep_clone(ty)
}
None => e.new_var(),
};
// Unify the pattern and the ty
e.unify(ty, patty)?;
// Infer the initializer
// Unify the initializer and the ty
todo!("Let: {l}")
if let Some(init) = init {
// Unify the initializer and the ty
let initty = init.infer(e)?;
e.unify(ty, initty)?;
}
Ok(ty)
}
ExprKind::Match(m) => {
let Match { scrutinee, arms } = m;
@ -270,10 +286,11 @@ pub mod inference {
impl<'a> Inference<'a> for Pattern {
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
match self {
Pattern::Name(name) => e
.table
.get_by_sym(e.at, name)
.ok_or(InferenceError::NotFound((*name).into())),
Pattern::Name(name) => {
let child = e.new_var();
e.table.add_child(e.at, *name, child);
Ok(child)
}
Pattern::Literal(literal) => literal.infer(e),
Pattern::Rest(_) => todo!("Infer rest-patterns"),
Pattern::Ref(_, pattern) => {
@ -336,15 +353,16 @@ pub mod inference {
impl<'a> Inference<'a> for Block {
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
let Block { stmts } = self;
let mut e = e.block_scope();
let empty = e.from_type_kind(TypeKind::Empty);
if let [stmts @ .., ret] = stmts.as_slice() {
for stmt in stmts {
match (&stmt.kind, &stmt.semi) {
(StmtKind::Expr(expr), Semi::Terminated) => {
expr.infer(e)?;
expr.infer(&mut e)?;
}
(StmtKind::Expr(expr), Semi::Unterminated) => {
let ty = expr.infer(e)?;
let ty = expr.infer(&mut e)?;
e.unify(ty, empty)?;
}
_ => {}
@ -352,10 +370,10 @@ pub mod inference {
}
match (&ret.kind, &ret.semi) {
(StmtKind::Expr(expr), Semi::Terminated) => {
expr.infer(e)?;
expr.infer(&mut e)?;
}
(StmtKind::Expr(expr), Semi::Unterminated) => {
return expr.infer(e);
return expr.infer(&mut e);
}
_ => {}
}

View File

@ -2,7 +2,7 @@ use super::error::InferenceError;
use crate::{
entry::Entry,
handle::Handle,
table::Table,
table::{NodeKind, Table},
type_expression::TypeExpression,
type_kind::{Adt, TypeKind},
};
@ -40,16 +40,16 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
Self { at, table, bset: never, rset: never }
}
pub fn at<'b>(&'b mut self, at: Handle) -> InferenceEngine<'b, 'a> {
pub fn at(&mut self, at: Handle) -> InferenceEngine<'_, 'a> {
InferenceEngine { at, table: self.table, bset: self.bset, rset: self.rset }
}
pub fn open_bset<'b>(&'b mut self) -> InferenceEngine<'b, 'a> {
pub fn open_bset(&mut self) -> InferenceEngine<'_, 'a> {
let bset = self.from_type_kind(TypeKind::Empty);
InferenceEngine { at: self.at, table: self.table, bset, rset: self.rset }
}
pub fn open_rset<'b>(&'b mut self) -> InferenceEngine<'b, 'a> {
pub fn open_rset(&mut self) -> InferenceEngine<'_, 'a> {
let rset = self.new_var();
InferenceEngine { at: self.at, table: self.table, bset: self.bset, rset }
}
@ -106,6 +106,18 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
self.table.get_by_sym(self.table.root(), &name)
}
/// Enters a new scope
pub fn local_scope(&mut self) {
let scope = self.table.new_entry(self.at, NodeKind::Local);
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);
self.at(scope)
}
/// Sets this type variable `to` be an instance `of` the other
/// # Panics
/// Panics if `to` is not a type variable