cl-typeck: Early type inference for let
This commit is contained in:
parent
65b75f95ce
commit
3b96833fcb
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user