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.
|
/// A [TypedInterner] hands out [Interned] references for arbitrary types.
|
||||||
///
|
///
|
||||||
/// See the [module-level documentation](self) for more information.
|
/// See the [module-level documentation](self) for more information.
|
||||||
#[derive(Default)]
|
|
||||||
pub struct TypedInterner<'a, T: Eq + Hash> {
|
pub struct TypedInterner<'a, T: Eq + Hash> {
|
||||||
arena: TypedArena<'a, T>,
|
arena: TypedArena<'a, T>,
|
||||||
keys: RwLock<HashSet<&'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> {
|
impl<'a, T: Eq + Hash> TypedInterner<'a, T> {
|
||||||
/// Creates a new [TypedInterner] backed by the provided [TypedArena]
|
/// Creates a new [TypedInterner] backed by the provided [TypedArena]
|
||||||
pub fn new(arena: TypedArena<'a, T>) -> Self {
|
pub fn new(arena: TypedArena<'a, T>) -> Self {
|
||||||
|
@ -13,7 +13,7 @@ pub mod inference {
|
|||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use super::{engine::InferenceEngine, error::InferenceError};
|
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::*;
|
use cl_ast::*;
|
||||||
|
|
||||||
pub trait Inference<'a> {
|
pub trait Inference<'a> {
|
||||||
@ -33,12 +33,28 @@ pub mod inference {
|
|||||||
ExprKind::Empty => Ok(e.from_type_kind(TypeKind::Empty)),
|
ExprKind::Empty => Ok(e.from_type_kind(TypeKind::Empty)),
|
||||||
ExprKind::Quote(quote) => todo!("Quote: {quote}"),
|
ExprKind::Quote(quote) => todo!("Quote: {quote}"),
|
||||||
ExprKind::Let(l) => {
|
ExprKind::Let(l) => {
|
||||||
|
let Let { mutable: _, name, ty, init } = l;
|
||||||
// Infer the pattern
|
// Infer the pattern
|
||||||
|
let patty = name.infer(e)?;
|
||||||
// Deep copy the ty, if it exists
|
// 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
|
// Unify the pattern and the ty
|
||||||
|
e.unify(ty, patty)?;
|
||||||
// Infer the initializer
|
// Infer the initializer
|
||||||
// Unify the initializer and the ty
|
if let Some(init) = init {
|
||||||
todo!("Let: {l}")
|
// Unify the initializer and the ty
|
||||||
|
let initty = init.infer(e)?;
|
||||||
|
e.unify(ty, initty)?;
|
||||||
|
}
|
||||||
|
Ok(ty)
|
||||||
}
|
}
|
||||||
ExprKind::Match(m) => {
|
ExprKind::Match(m) => {
|
||||||
let Match { scrutinee, arms } = m;
|
let Match { scrutinee, arms } = m;
|
||||||
@ -270,10 +286,11 @@ pub mod inference {
|
|||||||
impl<'a> Inference<'a> for Pattern {
|
impl<'a> Inference<'a> for Pattern {
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
||||||
match self {
|
match self {
|
||||||
Pattern::Name(name) => e
|
Pattern::Name(name) => {
|
||||||
.table
|
let child = e.new_var();
|
||||||
.get_by_sym(e.at, name)
|
e.table.add_child(e.at, *name, child);
|
||||||
.ok_or(InferenceError::NotFound((*name).into())),
|
Ok(child)
|
||||||
|
}
|
||||||
Pattern::Literal(literal) => literal.infer(e),
|
Pattern::Literal(literal) => literal.infer(e),
|
||||||
Pattern::Rest(_) => todo!("Infer rest-patterns"),
|
Pattern::Rest(_) => todo!("Infer rest-patterns"),
|
||||||
Pattern::Ref(_, pattern) => {
|
Pattern::Ref(_, pattern) => {
|
||||||
@ -336,15 +353,16 @@ pub mod inference {
|
|||||||
impl<'a> Inference<'a> for Block {
|
impl<'a> Inference<'a> for Block {
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
||||||
let Block { stmts } = self;
|
let Block { stmts } = self;
|
||||||
|
let mut e = e.block_scope();
|
||||||
let empty = e.from_type_kind(TypeKind::Empty);
|
let empty = e.from_type_kind(TypeKind::Empty);
|
||||||
if let [stmts @ .., ret] = stmts.as_slice() {
|
if let [stmts @ .., ret] = stmts.as_slice() {
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
match (&stmt.kind, &stmt.semi) {
|
match (&stmt.kind, &stmt.semi) {
|
||||||
(StmtKind::Expr(expr), Semi::Terminated) => {
|
(StmtKind::Expr(expr), Semi::Terminated) => {
|
||||||
expr.infer(e)?;
|
expr.infer(&mut e)?;
|
||||||
}
|
}
|
||||||
(StmtKind::Expr(expr), Semi::Unterminated) => {
|
(StmtKind::Expr(expr), Semi::Unterminated) => {
|
||||||
let ty = expr.infer(e)?;
|
let ty = expr.infer(&mut e)?;
|
||||||
e.unify(ty, empty)?;
|
e.unify(ty, empty)?;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -352,10 +370,10 @@ pub mod inference {
|
|||||||
}
|
}
|
||||||
match (&ret.kind, &ret.semi) {
|
match (&ret.kind, &ret.semi) {
|
||||||
(StmtKind::Expr(expr), Semi::Terminated) => {
|
(StmtKind::Expr(expr), Semi::Terminated) => {
|
||||||
expr.infer(e)?;
|
expr.infer(&mut e)?;
|
||||||
}
|
}
|
||||||
(StmtKind::Expr(expr), Semi::Unterminated) => {
|
(StmtKind::Expr(expr), Semi::Unterminated) => {
|
||||||
return expr.infer(e);
|
return expr.infer(&mut e);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use super::error::InferenceError;
|
|||||||
use crate::{
|
use crate::{
|
||||||
entry::Entry,
|
entry::Entry,
|
||||||
handle::Handle,
|
handle::Handle,
|
||||||
table::Table,
|
table::{NodeKind, Table},
|
||||||
type_expression::TypeExpression,
|
type_expression::TypeExpression,
|
||||||
type_kind::{Adt, TypeKind},
|
type_kind::{Adt, TypeKind},
|
||||||
};
|
};
|
||||||
@ -40,16 +40,16 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
Self { at, table, bset: never, rset: never }
|
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 }
|
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);
|
let bset = self.from_type_kind(TypeKind::Empty);
|
||||||
InferenceEngine { at: self.at, table: self.table, bset, rset: self.rset }
|
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();
|
let rset = self.new_var();
|
||||||
InferenceEngine { at: self.at, table: self.table, bset: self.bset, rset }
|
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)
|
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
|
/// Sets this type variable `to` be an instance `of` the other
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// Panics if `to` is not a type variable
|
/// Panics if `to` is not a type variable
|
||||||
|
Loading…
x
Reference in New Issue
Block a user