cl-typeck/infer: Fix some inference errors
yay yippee type checking and inference woohoo i am very tired
This commit is contained in:
parent
3b96833fcb
commit
7cf485fade
@ -7,421 +7,6 @@
|
|||||||
|
|
||||||
pub mod engine;
|
pub mod engine;
|
||||||
|
|
||||||
|
pub mod inference;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
pub mod inference {
|
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
use super::{engine::InferenceEngine, error::InferenceError};
|
|
||||||
use crate::{handle::Handle, type_expression::TypeExpression, type_kind::TypeKind};
|
|
||||||
use cl_ast::*;
|
|
||||||
|
|
||||||
pub trait Inference<'a> {
|
|
||||||
/// Performs type inference
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for cl_ast::Expr {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
|
||||||
self.kind.infer(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for cl_ast::ExprKind {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
|
||||||
match self {
|
|
||||||
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
|
|
||||||
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;
|
|
||||||
// Infer the scrutinee
|
|
||||||
let scrutinee = scrutinee.infer(e)?;
|
|
||||||
|
|
||||||
let scope = e.new_var();
|
|
||||||
for arm in arms {
|
|
||||||
let _ty = arm.infer(e)?;
|
|
||||||
}
|
|
||||||
// For each pattern:
|
|
||||||
// Infer the pattern
|
|
||||||
// Unify it with the scrutinee
|
|
||||||
// Infer the Expr
|
|
||||||
// Unify the expr with the out variable
|
|
||||||
// Return out
|
|
||||||
todo!("Match: {m} {scrutinee} {scope}")
|
|
||||||
}
|
|
||||||
ExprKind::Assign(assign) => {
|
|
||||||
// Infer the tail expression
|
|
||||||
// Infer the head expression
|
|
||||||
// Unify head and tail
|
|
||||||
// Return Empty
|
|
||||||
todo!("Assign {assign}")
|
|
||||||
}
|
|
||||||
ExprKind::Modify(modify) => {
|
|
||||||
// Infer the tail expression
|
|
||||||
// Infer the head expression
|
|
||||||
// Search within the head type for `(op)_assign`
|
|
||||||
// Typecheck `op_assign(&mut head, tail)`
|
|
||||||
todo!("Modify {modify}")
|
|
||||||
}
|
|
||||||
ExprKind::Binary(binary) => {
|
|
||||||
let Binary { kind: _, parts } = binary;
|
|
||||||
let (head, tail) = parts.as_ref();
|
|
||||||
// Infer the tail expression
|
|
||||||
let tail = tail.infer(e)?;
|
|
||||||
// Infer the head expression
|
|
||||||
let head = head.infer(e)?;
|
|
||||||
// TODO: Search within the head type for `(op)`
|
|
||||||
e.unify(head, tail)?;
|
|
||||||
// Typecheck op(head, tail)
|
|
||||||
Ok(head)
|
|
||||||
}
|
|
||||||
ExprKind::Unary(unary) => {
|
|
||||||
let Unary { kind: _, tail } = unary;
|
|
||||||
// Infer the tail expression
|
|
||||||
let tail = tail.infer(e)?;
|
|
||||||
// TODO: Search within the tail type for `(op)`
|
|
||||||
|
|
||||||
// Typecheck `(op)(tail)`
|
|
||||||
Ok(tail)
|
|
||||||
}
|
|
||||||
ExprKind::Cast(cast) => {
|
|
||||||
// Infer the head expression
|
|
||||||
// Evaluate the type
|
|
||||||
// Decide whether the type is castable
|
|
||||||
// Return the type
|
|
||||||
todo!("Cast {cast}")
|
|
||||||
}
|
|
||||||
ExprKind::Member(member) => {
|
|
||||||
let Member { head, kind } = member;
|
|
||||||
// Infer the head expression
|
|
||||||
let head = head.infer(e)?;
|
|
||||||
// Get the type of head
|
|
||||||
let ty = e.entry(e.de_inst(head));
|
|
||||||
// Search within the head type for the memberkind
|
|
||||||
match kind {
|
|
||||||
MemberKind::Call(name, tuple) => match ty.nav(&[PathPart::Ident(*name)]) {
|
|
||||||
Some(ty) => match e.entry(e.de_inst(ty.id())).ty() {
|
|
||||||
Some(&TypeKind::FnSig { args, rety }) => {
|
|
||||||
let values = iter::once(Ok(ty.id()))
|
|
||||||
.chain(
|
|
||||||
tuple
|
|
||||||
.exprs
|
|
||||||
.iter()
|
|
||||||
// Infer each member
|
|
||||||
.map(|expr| expr.infer(e)),
|
|
||||||
)
|
|
||||||
// Construct tuple
|
|
||||||
.collect::<Result<Vec<_>, InferenceError>>()
|
|
||||||
// Return tuple
|
|
||||||
.map(|tys| e.from_type_kind(TypeKind::Tuple(tys)))?;
|
|
||||||
e.unify(args, values)?;
|
|
||||||
Ok(rety)
|
|
||||||
}
|
|
||||||
other => todo!("member-call {other:?}"),
|
|
||||||
},
|
|
||||||
None => Err(InferenceError::NotFound(Path::from(*name))),
|
|
||||||
},
|
|
||||||
MemberKind::Struct(name) => match ty.nav(&[PathPart::Ident(*name)]) {
|
|
||||||
Some(ty) => Ok(ty.id()),
|
|
||||||
None => Err(InferenceError::NotFound(Path::from(*name))),
|
|
||||||
},
|
|
||||||
MemberKind::Tuple(Literal::Int(idx)) => match ty.ty() {
|
|
||||||
Some(TypeKind::Tuple(tys)) => Ok(tys[*idx as usize]),
|
|
||||||
_ => Err(InferenceError::Mismatch(ty.id(), e.table.root())),
|
|
||||||
},
|
|
||||||
_ => Err(InferenceError::Mismatch(ty.id(), ty.root())),
|
|
||||||
}
|
|
||||||
// Type is required to be inferred at this point.
|
|
||||||
}
|
|
||||||
ExprKind::Index(index) => {
|
|
||||||
// Infer the head expression
|
|
||||||
// For each index expression:
|
|
||||||
// Infer the index type
|
|
||||||
// Decide whether the head can be indexed by that type
|
|
||||||
// head = result of indexing head
|
|
||||||
todo!("Index {index}")
|
|
||||||
}
|
|
||||||
ExprKind::Structor(structor) => {
|
|
||||||
// Evaluate the path in the current context
|
|
||||||
// Typecheck the fielders against the fields
|
|
||||||
todo!("Structor {structor}")
|
|
||||||
}
|
|
||||||
ExprKind::Path(path) => e
|
|
||||||
.by_name(path)
|
|
||||||
.map_err(|_| InferenceError::NotFound(path.clone())),
|
|
||||||
ExprKind::Literal(literal) => literal.infer(e),
|
|
||||||
ExprKind::Array(array) => {
|
|
||||||
let Array { values } = array;
|
|
||||||
let out = e.new_var();
|
|
||||||
for value in values {
|
|
||||||
let ty = value.infer(e)?;
|
|
||||||
e.unify(out, ty)?;
|
|
||||||
}
|
|
||||||
Ok(out)
|
|
||||||
}
|
|
||||||
ExprKind::ArrayRep(array_rep) => {
|
|
||||||
let ArrayRep { value, repeat } = array_rep;
|
|
||||||
let ty = value.infer(e)?;
|
|
||||||
Ok(e.from_type_kind(TypeKind::Array(ty, *repeat)))
|
|
||||||
}
|
|
||||||
ExprKind::AddrOf(addr_of) => {
|
|
||||||
let AddrOf { mutable: _, expr } = addr_of;
|
|
||||||
// TODO: mut ref
|
|
||||||
let ty = expr.infer(e)?;
|
|
||||||
Ok(e.from_type_kind(TypeKind::Ref(ty)))
|
|
||||||
}
|
|
||||||
ExprKind::Block(block) => block.infer(e),
|
|
||||||
ExprKind::Group(group) => {
|
|
||||||
let Group { expr } = group;
|
|
||||||
expr.infer(e)
|
|
||||||
}
|
|
||||||
ExprKind::Tuple(tuple) => tuple.infer(e),
|
|
||||||
|
|
||||||
ExprKind::While(w) => {
|
|
||||||
let While { cond, pass, fail } = w;
|
|
||||||
// Infer the condition
|
|
||||||
let cond = cond.infer(e)?;
|
|
||||||
// Unify the condition with bool
|
|
||||||
let boule = e
|
|
||||||
.primitive("bool".into())
|
|
||||||
.expect("Primitive bool should exist!");
|
|
||||||
e.unify(boule, cond)?;
|
|
||||||
// Enter a new breakset
|
|
||||||
let mut e = e.open_bset();
|
|
||||||
|
|
||||||
// Infer the fail branch
|
|
||||||
let fail = fail.infer(&mut e)?;
|
|
||||||
// Unify the fail branch with breakset
|
|
||||||
e.bset = fail;
|
|
||||||
|
|
||||||
// Infer the pass branch
|
|
||||||
let pass = pass.infer(&mut e)?;
|
|
||||||
// Unify the pass branch with Empty
|
|
||||||
let empt = e.from_type_kind(TypeKind::Empty);
|
|
||||||
e.unify(pass, empt)?;
|
|
||||||
|
|
||||||
// Return breakset
|
|
||||||
Ok(e.bset)
|
|
||||||
}
|
|
||||||
ExprKind::If(i) => {
|
|
||||||
let If { cond, pass, fail } = i;
|
|
||||||
// Do inference on the condition'
|
|
||||||
let cond = cond.infer(e)?;
|
|
||||||
// Unify the condition with bool
|
|
||||||
let boule = e
|
|
||||||
.primitive("bool".into())
|
|
||||||
.expect("Primitive bool should exist!");
|
|
||||||
e.unify(boule, cond)?;
|
|
||||||
// Do inference on the pass branch
|
|
||||||
let pass = pass.infer(e)?;
|
|
||||||
// Do inference on the fail branch
|
|
||||||
let fail = fail.infer(e)?;
|
|
||||||
// Unify pass and fail
|
|
||||||
e.unify(pass, fail)?;
|
|
||||||
// Return the result
|
|
||||||
Ok(pass)
|
|
||||||
}
|
|
||||||
ExprKind::For(f) => todo!("For {f}"),
|
|
||||||
ExprKind::Break(b) => {
|
|
||||||
let Break { body } = b;
|
|
||||||
// Infer the body of the break
|
|
||||||
let ty = body.infer(e)?;
|
|
||||||
// Unify it with the breakset of the loop
|
|
||||||
e.unify(ty, e.bset)?;
|
|
||||||
// Return never
|
|
||||||
Ok(e.from_type_kind(TypeKind::Never))
|
|
||||||
}
|
|
||||||
ExprKind::Return(r) => {
|
|
||||||
let Return { body } = r;
|
|
||||||
// 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)?;
|
|
||||||
// Return never
|
|
||||||
Ok(e.from_type_kind(TypeKind::Never))
|
|
||||||
}
|
|
||||||
ExprKind::Continue => Ok(e.from_type_kind(TypeKind::Never)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for MatchArm {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
|
||||||
let MatchArm(pat, expr) = self;
|
|
||||||
let table = &mut e.table;
|
|
||||||
let scope = table.new_entry(e.at, crate::table::NodeKind::Local);
|
|
||||||
let mut e = e.at(scope);
|
|
||||||
|
|
||||||
let pat_ty = pat.infer(&mut e)?;
|
|
||||||
// TODO: bind pattern variables in scope
|
|
||||||
let expr_ty = expr.infer(&mut e)?;
|
|
||||||
todo!("Finish pattern-matching: {pat_ty}, {expr_ty}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Pattern {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
|
||||||
match self {
|
|
||||||
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) => {
|
|
||||||
let ty = pattern.infer(e)?;
|
|
||||||
Ok(e.from_type_kind(TypeKind::Ref(ty)))
|
|
||||||
}
|
|
||||||
Pattern::RangeExc(pat1, pat2) => {
|
|
||||||
let ty1 = pat1.infer(e)?;
|
|
||||||
let ty2 = pat2.infer(e)?;
|
|
||||||
e.unify(ty1, ty2)?;
|
|
||||||
Ok(ty1)
|
|
||||||
}
|
|
||||||
Pattern::RangeInc(pat1, pat2) => {
|
|
||||||
let ty1 = pat1.infer(e)?;
|
|
||||||
let ty2 = pat2.infer(e)?;
|
|
||||||
e.unify(ty1, ty2)?;
|
|
||||||
Ok(ty1)
|
|
||||||
}
|
|
||||||
Pattern::Tuple(patterns) => {
|
|
||||||
let tys = patterns
|
|
||||||
.iter()
|
|
||||||
.map(|pat| pat.infer(e))
|
|
||||||
.collect::<Result<Vec<Handle>, InferenceError>>()?;
|
|
||||||
Ok(e.from_type_kind(TypeKind::Tuple(tys)))
|
|
||||||
}
|
|
||||||
Pattern::Array(patterns) => match patterns.as_slice() {
|
|
||||||
[one, rest @ ..] => {
|
|
||||||
let ty = one.infer(e)?;
|
|
||||||
for rest in rest {
|
|
||||||
let ty2 = rest.infer(e)?;
|
|
||||||
e.unify(ty, ty2)?;
|
|
||||||
}
|
|
||||||
Ok(e.from_type_kind(TypeKind::Slice(ty)))
|
|
||||||
}
|
|
||||||
[] => {
|
|
||||||
let ty = e.new_var();
|
|
||||||
Ok(e.from_type_kind(TypeKind::Slice(ty)))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Pattern::Struct(_path, _items) => todo!(),
|
|
||||||
Pattern::TupleStruct(_path, _patterns) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Tuple {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
|
||||||
let Tuple { exprs } = self;
|
|
||||||
exprs
|
|
||||||
.iter()
|
|
||||||
// Infer each member
|
|
||||||
.map(|expr| expr.infer(e))
|
|
||||||
// Construct tuple
|
|
||||||
.collect::<Result<Vec<_>, InferenceError>>()
|
|
||||||
// Return tuple
|
|
||||||
.map(|tys| e.from_type_kind(TypeKind::Tuple(tys)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(&mut e)?;
|
|
||||||
}
|
|
||||||
(StmtKind::Expr(expr), Semi::Unterminated) => {
|
|
||||||
let ty = expr.infer(&mut e)?;
|
|
||||||
e.unify(ty, empty)?;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match (&ret.kind, &ret.semi) {
|
|
||||||
(StmtKind::Expr(expr), Semi::Terminated) => {
|
|
||||||
expr.infer(&mut e)?;
|
|
||||||
}
|
|
||||||
(StmtKind::Expr(expr), Semi::Unterminated) => {
|
|
||||||
return expr.infer(&mut e);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(empty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Else {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
|
||||||
self.body.infer(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, I: Inference<'a>> Inference<'a> for Option<I> {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
|
||||||
match self {
|
|
||||||
Some(expr) => expr.infer(e),
|
|
||||||
None => Ok(e.from_type_kind(TypeKind::Empty)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a, I: Inference<'a>> Inference<'a> for Box<I> {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
|
||||||
self.as_ref().infer(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Literal {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
|
||||||
let ty = match self {
|
|
||||||
Literal::Bool(_) => Ok(e
|
|
||||||
.primitive("bool".into())
|
|
||||||
.expect("Primitive bool should exist!")),
|
|
||||||
Literal::Char(_) => Ok(e
|
|
||||||
.primitive("char".into())
|
|
||||||
.expect("Primitive char should exist!")),
|
|
||||||
Literal::Int(_) => Ok(e
|
|
||||||
.primitive("isize".into())
|
|
||||||
.expect("Primitive isize should exist!")),
|
|
||||||
Literal::Float(_) => Ok(e
|
|
||||||
.primitive("f64".into())
|
|
||||||
.expect("Primitive f64 should exist!")),
|
|
||||||
Literal::String(_) => Ok(e
|
|
||||||
.primitive("str".into())
|
|
||||||
.expect("Primitive str should exist!")),
|
|
||||||
}?;
|
|
||||||
Ok(e.new_inst(ty))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -45,7 +45,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_bset(&mut self) -> InferenceEngine<'_, 'a> {
|
pub fn open_bset(&mut self) -> InferenceEngine<'_, 'a> {
|
||||||
let bset = self.from_type_kind(TypeKind::Empty);
|
let bset = self.new_var();
|
||||||
InferenceEngine { at: self.at, table: self.table, bset, rset: self.rset }
|
InferenceEngine { at: self.at, table: self.table, bset, rset: self.rset }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +124,12 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
pub fn set_instance(&mut self, to: Handle, of: Handle) {
|
pub fn set_instance(&mut self, to: Handle, of: Handle) {
|
||||||
let mut e = self.table.entry_mut(to);
|
let mut e = self.table.entry_mut(to);
|
||||||
match e.as_ref().ty() {
|
match e.as_ref().ty() {
|
||||||
|
Some(TypeKind::Uninferred) => {
|
||||||
|
if let Some(ty) = self.table.ty(of) {
|
||||||
|
self.table.set_ty(to, ty.clone());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
Some(TypeKind::Variable) => e.set_ty(TypeKind::Instance(of)),
|
Some(TypeKind::Variable) => e.set_ty(TypeKind::Instance(of)),
|
||||||
other => todo!("Cannot set {} to instance of: {other:?}", e.as_ref()),
|
other => todo!("Cannot set {} to instance of: {other:?}", e.as_ref()),
|
||||||
};
|
};
|
||||||
@ -355,12 +361,21 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
if a.len() != b.len() {
|
if a.len() != b.len() {
|
||||||
return Err(InferenceError::Mismatch(ah, bh));
|
return Err(InferenceError::Mismatch(ah, bh));
|
||||||
}
|
}
|
||||||
|
let (a, b) = (a.clone(), b.clone());
|
||||||
|
for (a, b) in a.iter().zip(b.iter()) {
|
||||||
|
self.unify(*a, *b)?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
(&TypeKind::FnSig { args: a1, rety: r1 }, &TypeKind::FnSig { args: a2, rety: r2 }) => {
|
(&TypeKind::FnSig { args: a1, rety: r1 }, &TypeKind::FnSig { args: a2, rety: r2 }) => {
|
||||||
self.unify(a1, a2)?;
|
self.unify(a1, a2)?;
|
||||||
self.unify(r1, r2)
|
self.unify(r1, r2)
|
||||||
}
|
}
|
||||||
|
(TypeKind::Empty, TypeKind::Tuple(t)) | (TypeKind::Tuple(t), TypeKind::Empty)
|
||||||
|
if t.is_empty() =>
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
(TypeKind::Empty, TypeKind::Empty) => Ok(()),
|
(TypeKind::Empty, TypeKind::Empty) => Ok(()),
|
||||||
(TypeKind::Never, _) | (_, TypeKind::Never) => Ok(()),
|
(TypeKind::Never, _) | (_, TypeKind::Never) => Ok(()),
|
||||||
(TypeKind::Module, TypeKind::Module) => Ok(()),
|
(TypeKind::Module, TypeKind::Module) => Ok(()),
|
||||||
|
@ -6,6 +6,7 @@ use core::fmt;
|
|||||||
/// An error produced during type inference
|
/// An error produced during type inference
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum InferenceError {
|
pub enum InferenceError {
|
||||||
|
AnnotationEval(crate::type_expression::Error),
|
||||||
NotFound(Path),
|
NotFound(Path),
|
||||||
Mismatch(Handle, Handle),
|
Mismatch(Handle, Handle),
|
||||||
Recursive(Handle, Handle),
|
Recursive(Handle, Handle),
|
||||||
@ -15,6 +16,7 @@ impl std::error::Error for InferenceError {}
|
|||||||
impl fmt::Display for InferenceError {
|
impl fmt::Display for InferenceError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
InferenceError::AnnotationEval(error) => write!(f, "{error}"),
|
||||||
InferenceError::NotFound(p) => write!(f, "Path not visible in scope: {p}"),
|
InferenceError::NotFound(p) => write!(f, "Path not visible in scope: {p}"),
|
||||||
InferenceError::Mismatch(a, b) => write!(f, "Type mismatch: {a:?} != {b:?}"),
|
InferenceError::Mismatch(a, b) => write!(f, "Type mismatch: {a:?} != {b:?}"),
|
||||||
InferenceError::Recursive(_, _) => write!(f, "Recursive type!"),
|
InferenceError::Recursive(_, _) => write!(f, "Recursive type!"),
|
||||||
|
454
compiler/cl-typeck/src/stage/infer/inference.rs
Normal file
454
compiler/cl-typeck/src/stage/infer/inference.rs
Normal file
@ -0,0 +1,454 @@
|
|||||||
|
//! The [Inference] trait is the heart of cl-typeck's type inference.
|
||||||
|
//!
|
||||||
|
//! Each syntax structure must describe how to unify its types.
|
||||||
|
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
|
use super::{engine::InferenceEngine, error::InferenceError};
|
||||||
|
use crate::{handle::Handle, type_expression::TypeExpression, type_kind::TypeKind};
|
||||||
|
use cl_ast::*;
|
||||||
|
|
||||||
|
pub trait Inference<'a> {
|
||||||
|
/// Performs type inference
|
||||||
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Inference<'a> for cl_ast::Expr {
|
||||||
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
||||||
|
self.kind.infer(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Inference<'a> for cl_ast::ExprKind {
|
||||||
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
||||||
|
match self {
|
||||||
|
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
|
||||||
|
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;
|
||||||
|
// Infer the scrutinee
|
||||||
|
let scrutinee = scrutinee.infer(e)?;
|
||||||
|
|
||||||
|
let scope = e.new_var();
|
||||||
|
for arm in arms {
|
||||||
|
let _ty = arm.infer(e)?;
|
||||||
|
}
|
||||||
|
// For each pattern:
|
||||||
|
// Infer the pattern
|
||||||
|
// Unify it with the scrutinee
|
||||||
|
// Infer the Expr
|
||||||
|
// Unify the expr with the out variable
|
||||||
|
// Return out
|
||||||
|
todo!("Match: {m} {scrutinee} {scope}")
|
||||||
|
}
|
||||||
|
ExprKind::Assign(assign) => {
|
||||||
|
let Assign { parts } = assign;
|
||||||
|
let (head, tail) = parts.as_ref();
|
||||||
|
// Infer the tail expression
|
||||||
|
let tail = tail.infer(e)?;
|
||||||
|
// Infer the head expression
|
||||||
|
let head = head.infer(e)?;
|
||||||
|
// Unify head and tail
|
||||||
|
e.unify(head, tail)?;
|
||||||
|
// Return Empty
|
||||||
|
Ok(e.from_type_kind(TypeKind::Empty))
|
||||||
|
}
|
||||||
|
ExprKind::Modify(modify) => {
|
||||||
|
let Modify { kind: _, parts } = modify;
|
||||||
|
let (head, tail) = parts.as_ref();
|
||||||
|
// Infer the tail expression
|
||||||
|
let tail = tail.infer(e)?;
|
||||||
|
// Infer the head expression
|
||||||
|
let head = head.infer(e)?;
|
||||||
|
// TODO: Search within the head type for `(op)_assign`
|
||||||
|
e.unify(head, tail)?;
|
||||||
|
// TODO: Typecheck `op_assign(&mut head, tail)`
|
||||||
|
Ok(e.from_type_kind(TypeKind::Empty))
|
||||||
|
}
|
||||||
|
ExprKind::Binary(binary) => {
|
||||||
|
let Binary { kind, parts } = binary;
|
||||||
|
let (head, tail) = parts.as_ref();
|
||||||
|
// Infer the tail expression
|
||||||
|
let tail = tail.infer(e)?;
|
||||||
|
// Infer the head expression
|
||||||
|
let head = head.infer(e)?;
|
||||||
|
// TODO: Search within the head type for `(op)`
|
||||||
|
if let BinaryKind::Call = kind {
|
||||||
|
let rety = e.new_var();
|
||||||
|
let tail = e.from_type_kind(TypeKind::FnSig { args: tail, rety });
|
||||||
|
e.unify(head, tail)?;
|
||||||
|
Ok(rety)
|
||||||
|
} else {
|
||||||
|
// Typecheck op(head, tail)
|
||||||
|
e.unify(head, tail)?;
|
||||||
|
Ok(head)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExprKind::Unary(Unary { kind: UnaryKind::Loop, tail }) => {
|
||||||
|
let mut e = e.block_scope();
|
||||||
|
// Enter a new breakset
|
||||||
|
let mut e = e.open_bset();
|
||||||
|
|
||||||
|
// Infer the fail branch
|
||||||
|
let tail = tail.infer(&mut e)?;
|
||||||
|
// Unify the pass branch with Empty
|
||||||
|
let empt = e.from_type_kind(TypeKind::Empty);
|
||||||
|
e.unify(tail, empt)?;
|
||||||
|
|
||||||
|
// Return breakset
|
||||||
|
Ok(e.bset)
|
||||||
|
}
|
||||||
|
ExprKind::Unary(unary) => {
|
||||||
|
let Unary { kind: _, tail } = unary;
|
||||||
|
// Infer the tail expression
|
||||||
|
let tail = tail.infer(e)?;
|
||||||
|
// TODO: Search within the tail type for `(op)`
|
||||||
|
// Typecheck `(op)(tail)`
|
||||||
|
Ok(tail)
|
||||||
|
}
|
||||||
|
ExprKind::Cast(cast) => {
|
||||||
|
let Cast { head, ty } = cast;
|
||||||
|
// Infer the head expression
|
||||||
|
let _head = head.infer(e)?;
|
||||||
|
// Evaluate the type
|
||||||
|
let ty = ty
|
||||||
|
.evaluate(e.table, e.at)
|
||||||
|
.map_err(InferenceError::AnnotationEval)?;
|
||||||
|
// Decide whether the type is castable
|
||||||
|
// TODO: not deciding is absolutely unsound!!!
|
||||||
|
// Return the type
|
||||||
|
Ok(ty)
|
||||||
|
}
|
||||||
|
ExprKind::Member(member) => {
|
||||||
|
let Member { head, kind } = member;
|
||||||
|
// Infer the head expression
|
||||||
|
let head = head.infer(e)?;
|
||||||
|
// Get the type of head
|
||||||
|
let ty = e.entry(e.de_inst(head));
|
||||||
|
// Search within the head type for the memberkind
|
||||||
|
match kind {
|
||||||
|
MemberKind::Call(name, tuple) => match ty.nav(&[PathPart::Ident(*name)]) {
|
||||||
|
Some(ty) => match e.entry(e.de_inst(ty.id())).ty() {
|
||||||
|
Some(&TypeKind::FnSig { args, rety }) => {
|
||||||
|
let values = iter::once(Ok(ty.id()))
|
||||||
|
.chain(
|
||||||
|
tuple
|
||||||
|
.exprs
|
||||||
|
.iter()
|
||||||
|
// Infer each member
|
||||||
|
.map(|expr| expr.infer(e)),
|
||||||
|
)
|
||||||
|
// Construct tuple
|
||||||
|
.collect::<Result<Vec<_>, InferenceError>>()
|
||||||
|
// Return tuple
|
||||||
|
.map(|tys| e.from_type_kind(TypeKind::Tuple(tys)))?;
|
||||||
|
e.unify(args, values)?;
|
||||||
|
Ok(rety)
|
||||||
|
}
|
||||||
|
other => todo!("member-call {other:?}"),
|
||||||
|
},
|
||||||
|
None => Err(InferenceError::NotFound(Path::from(*name))),
|
||||||
|
},
|
||||||
|
MemberKind::Struct(name) => match ty.nav(&[PathPart::Ident(*name)]) {
|
||||||
|
Some(ty) => Ok(ty.id()),
|
||||||
|
None => Err(InferenceError::NotFound(Path::from(*name))),
|
||||||
|
},
|
||||||
|
MemberKind::Tuple(Literal::Int(idx)) => match ty.ty() {
|
||||||
|
Some(TypeKind::Tuple(tys)) => Ok(tys[*idx as usize]),
|
||||||
|
_ => Err(InferenceError::Mismatch(ty.id(), e.table.root())),
|
||||||
|
},
|
||||||
|
_ => Err(InferenceError::Mismatch(ty.id(), ty.root())),
|
||||||
|
}
|
||||||
|
// Type is required to be inferred at this point.
|
||||||
|
}
|
||||||
|
ExprKind::Index(index) => {
|
||||||
|
// Infer the head expression
|
||||||
|
// For each index expression:
|
||||||
|
// Infer the index type
|
||||||
|
// Decide whether the head can be indexed by that type
|
||||||
|
// head = result of indexing head
|
||||||
|
todo!("Index {index}")
|
||||||
|
}
|
||||||
|
ExprKind::Structor(structor) => {
|
||||||
|
// Evaluate the path in the current context
|
||||||
|
// Typecheck the fielders against the fields
|
||||||
|
todo!("Structor {structor}")
|
||||||
|
}
|
||||||
|
ExprKind::Path(path) => e
|
||||||
|
.by_name(path)
|
||||||
|
.map_err(|_| InferenceError::NotFound(path.clone())),
|
||||||
|
ExprKind::Literal(literal) => literal.infer(e),
|
||||||
|
ExprKind::Array(array) => {
|
||||||
|
let Array { values } = array;
|
||||||
|
let out = e.new_var();
|
||||||
|
for value in values {
|
||||||
|
let ty = value.infer(e)?;
|
||||||
|
e.unify(out, ty)?;
|
||||||
|
}
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
ExprKind::ArrayRep(array_rep) => {
|
||||||
|
let ArrayRep { value, repeat } = array_rep;
|
||||||
|
let ty = value.infer(e)?;
|
||||||
|
Ok(e.from_type_kind(TypeKind::Array(ty, *repeat)))
|
||||||
|
}
|
||||||
|
ExprKind::AddrOf(addr_of) => {
|
||||||
|
let AddrOf { mutable: _, expr } = addr_of;
|
||||||
|
// TODO: mut ref
|
||||||
|
let ty = expr.infer(e)?;
|
||||||
|
Ok(e.from_type_kind(TypeKind::Ref(ty)))
|
||||||
|
}
|
||||||
|
ExprKind::Block(block) => block.infer(e),
|
||||||
|
ExprKind::Group(group) => {
|
||||||
|
let Group { expr } = group;
|
||||||
|
expr.infer(e)
|
||||||
|
}
|
||||||
|
ExprKind::Tuple(tuple) => tuple.infer(e),
|
||||||
|
|
||||||
|
ExprKind::While(w) => {
|
||||||
|
let While { cond, pass, fail } = w;
|
||||||
|
// Infer the condition
|
||||||
|
let cond = cond.infer(e)?;
|
||||||
|
// Unify the condition with bool
|
||||||
|
let boule = e
|
||||||
|
.primitive("bool".into())
|
||||||
|
.expect("Primitive bool should exist!");
|
||||||
|
e.unify(boule, cond)?;
|
||||||
|
// Enter a new breakset
|
||||||
|
let mut e = e.open_bset();
|
||||||
|
|
||||||
|
// Infer the fail branch
|
||||||
|
let fail = fail.infer(&mut e)?;
|
||||||
|
// Unify the fail branch with breakset
|
||||||
|
e.bset = fail;
|
||||||
|
|
||||||
|
// Infer the pass branch
|
||||||
|
let pass = pass.infer(&mut e)?;
|
||||||
|
// Unify the pass branch with Empty
|
||||||
|
let empt = e.from_type_kind(TypeKind::Empty);
|
||||||
|
e.unify(pass, empt)?;
|
||||||
|
|
||||||
|
// Return breakset
|
||||||
|
Ok(e.bset)
|
||||||
|
}
|
||||||
|
ExprKind::If(i) => {
|
||||||
|
let If { cond, pass, fail } = i;
|
||||||
|
// Do inference on the condition'
|
||||||
|
let cond = cond.infer(e)?;
|
||||||
|
// Unify the condition with bool
|
||||||
|
let boule = e
|
||||||
|
.primitive("bool".into())
|
||||||
|
.expect("Primitive bool should exist!");
|
||||||
|
e.unify(boule, cond)?;
|
||||||
|
// Do inference on the pass branch
|
||||||
|
let pass = pass.infer(e)?;
|
||||||
|
// Do inference on the fail branch
|
||||||
|
let fail = fail.infer(e)?;
|
||||||
|
// Unify pass and fail
|
||||||
|
e.unify(pass, fail)?;
|
||||||
|
// Return the result
|
||||||
|
Ok(pass)
|
||||||
|
}
|
||||||
|
ExprKind::For(f) => todo!("For {f}"),
|
||||||
|
ExprKind::Break(b) => {
|
||||||
|
let Break { body } = b;
|
||||||
|
// Infer the body of the break
|
||||||
|
let ty = body.infer(e)?;
|
||||||
|
// Unify it with the breakset of the loop
|
||||||
|
e.unify(ty, e.bset)?;
|
||||||
|
// Return never
|
||||||
|
Ok(e.from_type_kind(TypeKind::Never))
|
||||||
|
}
|
||||||
|
ExprKind::Return(r) => {
|
||||||
|
let Return { body } = r;
|
||||||
|
// 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)?;
|
||||||
|
// Return never
|
||||||
|
Ok(e.from_type_kind(TypeKind::Never))
|
||||||
|
}
|
||||||
|
ExprKind::Continue => Ok(e.from_type_kind(TypeKind::Never)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Inference<'a> for MatchArm {
|
||||||
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
||||||
|
let MatchArm(pat, expr) = self;
|
||||||
|
let table = &mut e.table;
|
||||||
|
let scope = table.new_entry(e.at, crate::table::NodeKind::Local);
|
||||||
|
let mut e = e.at(scope);
|
||||||
|
|
||||||
|
let pat_ty = pat.infer(&mut e)?;
|
||||||
|
// TODO: bind pattern variables in scope
|
||||||
|
let expr_ty = expr.infer(&mut e)?;
|
||||||
|
todo!("Finish pattern-matching: {pat_ty}, {expr_ty}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Inference<'a> for Pattern {
|
||||||
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
||||||
|
match self {
|
||||||
|
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) => {
|
||||||
|
let ty = pattern.infer(e)?;
|
||||||
|
Ok(e.from_type_kind(TypeKind::Ref(ty)))
|
||||||
|
}
|
||||||
|
Pattern::RangeExc(pat1, pat2) => {
|
||||||
|
let ty1 = pat1.infer(e)?;
|
||||||
|
let ty2 = pat2.infer(e)?;
|
||||||
|
e.unify(ty1, ty2)?;
|
||||||
|
Ok(ty1)
|
||||||
|
}
|
||||||
|
Pattern::RangeInc(pat1, pat2) => {
|
||||||
|
let ty1 = pat1.infer(e)?;
|
||||||
|
let ty2 = pat2.infer(e)?;
|
||||||
|
e.unify(ty1, ty2)?;
|
||||||
|
Ok(ty1)
|
||||||
|
}
|
||||||
|
Pattern::Tuple(patterns) => {
|
||||||
|
let tys = patterns
|
||||||
|
.iter()
|
||||||
|
.map(|pat| pat.infer(e))
|
||||||
|
.collect::<Result<Vec<Handle>, InferenceError>>()?;
|
||||||
|
Ok(e.from_type_kind(TypeKind::Tuple(tys)))
|
||||||
|
}
|
||||||
|
Pattern::Array(patterns) => match patterns.as_slice() {
|
||||||
|
[one, rest @ ..] => {
|
||||||
|
let ty = one.infer(e)?;
|
||||||
|
for rest in rest {
|
||||||
|
let ty2 = rest.infer(e)?;
|
||||||
|
e.unify(ty, ty2)?;
|
||||||
|
}
|
||||||
|
Ok(e.from_type_kind(TypeKind::Slice(ty)))
|
||||||
|
}
|
||||||
|
[] => {
|
||||||
|
let ty = e.new_var();
|
||||||
|
Ok(e.from_type_kind(TypeKind::Slice(ty)))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Pattern::Struct(_path, _items) => todo!(),
|
||||||
|
Pattern::TupleStruct(_path, _patterns) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Inference<'a> for Tuple {
|
||||||
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
||||||
|
let Tuple { exprs } = self;
|
||||||
|
exprs
|
||||||
|
.iter()
|
||||||
|
// Infer each member
|
||||||
|
.map(|expr| expr.infer(e))
|
||||||
|
// Construct tuple
|
||||||
|
.collect::<Result<Vec<_>, InferenceError>>()
|
||||||
|
// Return tuple
|
||||||
|
.map(|tys| e.from_type_kind(TypeKind::Tuple(tys)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(&mut e)?;
|
||||||
|
}
|
||||||
|
(StmtKind::Expr(expr), Semi::Unterminated) => {
|
||||||
|
let ty = expr.infer(&mut e)?;
|
||||||
|
e.unify(ty, empty)?;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match (&ret.kind, &ret.semi) {
|
||||||
|
(StmtKind::Expr(expr), Semi::Terminated) => {
|
||||||
|
expr.infer(&mut e)?;
|
||||||
|
}
|
||||||
|
(StmtKind::Expr(expr), Semi::Unterminated) => {
|
||||||
|
return expr.infer(&mut e);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(empty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Inference<'a> for Else {
|
||||||
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
||||||
|
self.body.infer(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I: Inference<'a>> Inference<'a> for Option<I> {
|
||||||
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
||||||
|
match self {
|
||||||
|
Some(expr) => expr.infer(e),
|
||||||
|
None => Ok(e.from_type_kind(TypeKind::Empty)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, I: Inference<'a>> Inference<'a> for Box<I> {
|
||||||
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
||||||
|
self.as_ref().infer(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Inference<'a> for Literal {
|
||||||
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> Result<Handle, InferenceError> {
|
||||||
|
let ty = match self {
|
||||||
|
Literal::Bool(_) => Ok(e
|
||||||
|
.primitive("bool".into())
|
||||||
|
.expect("Primitive bool should exist!")),
|
||||||
|
Literal::Char(_) => Ok(e
|
||||||
|
.primitive("char".into())
|
||||||
|
.expect("Primitive char should exist!")),
|
||||||
|
Literal::Int(_) => Ok(e
|
||||||
|
.primitive("isize".into())
|
||||||
|
.expect("Primitive isize should exist!")),
|
||||||
|
Literal::Float(_) => Ok(e
|
||||||
|
.primitive("f64".into())
|
||||||
|
.expect("Primitive f64 should exist!")),
|
||||||
|
Literal::String(_) => Ok(e
|
||||||
|
.primitive("str".into())
|
||||||
|
.expect("Primitive str should exist!")),
|
||||||
|
}?;
|
||||||
|
Ok(e.new_inst(ty))
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user