Implement typechecking and inference logic for binops
This commit is contained in:
parent
2cb61de294
commit
7ba3204803
@ -1,8 +1,10 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use reid_lib::{builder::InstructionValue, Instr};
|
use reid_lib::{builder::InstructionValue, Instr};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::{ErrorKind, StackValueKind},
|
codegen::{ErrorKind, StackValueKind},
|
||||||
mir::{BinopDefinition, FunctionDefinition, TypeKind},
|
mir::{BinaryOperator, BinopDefinition, FunctionDefinition, FunctionDefinitionKind, TypeKind},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::scope::{Scope, StackValue};
|
use super::scope::{Scope, StackValue};
|
||||||
@ -16,6 +18,72 @@ pub fn form_intrinsics() -> Vec<FunctionDefinition> {
|
|||||||
pub fn form_intrinsic_binops() -> Vec<BinopDefinition> {
|
pub fn form_intrinsic_binops() -> Vec<BinopDefinition> {
|
||||||
let mut intrinsics = Vec::new();
|
let mut intrinsics = Vec::new();
|
||||||
|
|
||||||
|
intrinsics.push(BinopDefinition {
|
||||||
|
lhs: ("lhs".to_owned(), TypeKind::U32),
|
||||||
|
op: BinaryOperator::Add,
|
||||||
|
rhs: ("rhs".to_owned(), TypeKind::U32),
|
||||||
|
return_type: TypeKind::U32,
|
||||||
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(
|
||||||
|
|scope, lhs, rhs| scope.block.build(Instr::Add(lhs, rhs)).unwrap(),
|
||||||
|
))),
|
||||||
|
meta: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
|
intrinsics.push(BinopDefinition {
|
||||||
|
lhs: ("lhs".to_owned(), TypeKind::U16),
|
||||||
|
op: BinaryOperator::Add,
|
||||||
|
rhs: ("rhs".to_owned(), TypeKind::U16),
|
||||||
|
return_type: TypeKind::U16,
|
||||||
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(
|
||||||
|
|scope, lhs, rhs| scope.block.build(Instr::Add(lhs, rhs)).unwrap(),
|
||||||
|
))),
|
||||||
|
meta: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
|
intrinsics.push(BinopDefinition {
|
||||||
|
lhs: ("lhs".to_owned(), TypeKind::U32),
|
||||||
|
op: BinaryOperator::Mult,
|
||||||
|
rhs: ("rhs".to_owned(), TypeKind::U32),
|
||||||
|
return_type: TypeKind::U32,
|
||||||
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(
|
||||||
|
|scope, lhs, rhs| scope.block.build(Instr::Mul(lhs, rhs)).unwrap(),
|
||||||
|
))),
|
||||||
|
meta: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
|
intrinsics.push(BinopDefinition {
|
||||||
|
lhs: ("lhs".to_owned(), TypeKind::U16),
|
||||||
|
op: BinaryOperator::Mult,
|
||||||
|
rhs: ("rhs".to_owned(), TypeKind::U16),
|
||||||
|
return_type: TypeKind::U16,
|
||||||
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(
|
||||||
|
|scope, lhs, rhs| scope.block.build(Instr::Mul(lhs, rhs)).unwrap(),
|
||||||
|
))),
|
||||||
|
meta: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
|
intrinsics.push(BinopDefinition {
|
||||||
|
lhs: ("lhs".to_owned(), TypeKind::U32),
|
||||||
|
op: BinaryOperator::Minus,
|
||||||
|
rhs: ("rhs".to_owned(), TypeKind::U32),
|
||||||
|
return_type: TypeKind::U32,
|
||||||
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(
|
||||||
|
|scope, lhs, rhs| scope.block.build(Instr::Sub(lhs, rhs)).unwrap(),
|
||||||
|
))),
|
||||||
|
meta: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
|
intrinsics.push(BinopDefinition {
|
||||||
|
lhs: ("lhs".to_owned(), TypeKind::U16),
|
||||||
|
op: BinaryOperator::Minus,
|
||||||
|
rhs: ("rhs".to_owned(), TypeKind::U16),
|
||||||
|
return_type: TypeKind::U16,
|
||||||
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(
|
||||||
|
|scope, lhs, rhs| scope.block.build(Instr::Sub(lhs, rhs)).unwrap(),
|
||||||
|
))),
|
||||||
|
meta: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
intrinsics
|
intrinsics
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,56 +91,99 @@ pub trait IntrinsicFunction: std::fmt::Debug {
|
|||||||
fn codegen<'ctx, 'a>(
|
fn codegen<'ctx, 'a>(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope<'ctx, 'a>,
|
scope: &mut Scope<'ctx, 'a>,
|
||||||
params: &[InstructionValue],
|
params: &[&StackValue],
|
||||||
) -> Result<StackValue, ErrorKind>;
|
) -> Result<StackValue, ErrorKind>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct IntrinsicIAdd(TypeKind);
|
pub struct IntrinsicSimpleInstr<T>(T)
|
||||||
|
where
|
||||||
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
|
||||||
|
|
||||||
impl IntrinsicFunction for IntrinsicIAdd {
|
impl<T> std::fmt::Debug for IntrinsicSimpleInstr<T>
|
||||||
fn codegen<'ctx, 'a>(
|
where
|
||||||
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_tuple("IntrinsicSimpleInstr").finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleInstr<T>
|
||||||
|
where
|
||||||
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||||
|
{
|
||||||
|
fn codegen<'b, 'c>(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope<'ctx, 'a>,
|
scope: &mut Scope<'b, 'c>,
|
||||||
params: &[InstructionValue],
|
params: &[&StackValue],
|
||||||
) -> Result<StackValue, ErrorKind> {
|
) -> Result<StackValue, ErrorKind> {
|
||||||
let lhs = params.get(0).unwrap();
|
let lhs = params.get(0).unwrap();
|
||||||
let rhs = params.get(1).unwrap();
|
let rhs = params.get(1).unwrap();
|
||||||
let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
|
let instr = self.clone().0(scope, lhs.instr(), rhs.instr());
|
||||||
Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
Ok(StackValue(StackValueKind::Literal(instr), lhs.1.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
// impl IntrinsicFunction for IntrinsicIAdd {
|
||||||
pub struct IntrinsicUDiv(TypeKind);
|
// fn codegen<'ctx, 'a>(
|
||||||
|
// &self,
|
||||||
|
// scope: &mut Scope<'ctx, 'a>,
|
||||||
|
// params: &[InstructionValue],
|
||||||
|
// ) -> Result<StackValue, ErrorKind> {
|
||||||
|
// let lhs = params.get(0).unwrap();
|
||||||
|
// let rhs = params.get(1).unwrap();
|
||||||
|
// let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
|
||||||
|
// Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
impl IntrinsicFunction for IntrinsicUDiv {
|
// #[derive(Debug, Clone)]
|
||||||
fn codegen<'ctx, 'a>(
|
// pub struct IntrinsicIAdd(TypeKind);
|
||||||
&self,
|
|
||||||
scope: &mut Scope<'ctx, 'a>,
|
|
||||||
params: &[InstructionValue],
|
|
||||||
) -> Result<StackValue, ErrorKind> {
|
|
||||||
let lhs = params.get(0).unwrap();
|
|
||||||
let rhs = params.get(1).unwrap();
|
|
||||||
let add = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
|
|
||||||
Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
// impl IntrinsicFunction for IntrinsicIAdd {
|
||||||
pub struct IntrinsicUMod(TypeKind);
|
// fn codegen<'ctx, 'a>(
|
||||||
|
// &self,
|
||||||
|
// scope: &mut Scope<'ctx, 'a>,
|
||||||
|
// params: &[InstructionValue],
|
||||||
|
// ) -> Result<StackValue, ErrorKind> {
|
||||||
|
// let lhs = params.get(0).unwrap();
|
||||||
|
// let rhs = params.get(1).unwrap();
|
||||||
|
// let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
|
||||||
|
// Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
impl IntrinsicFunction for IntrinsicUMod {
|
// #[derive(Debug, Clone)]
|
||||||
fn codegen<'ctx, 'a>(
|
// pub struct IntrinsicUDiv(TypeKind);
|
||||||
&self,
|
|
||||||
scope: &mut Scope<'ctx, 'a>,
|
// impl IntrinsicFunction for IntrinsicUDiv {
|
||||||
params: &[InstructionValue],
|
// fn codegen<'ctx, 'a>(
|
||||||
) -> Result<StackValue, ErrorKind> {
|
// &self,
|
||||||
let lhs = params.get(0).unwrap();
|
// scope: &mut Scope<'ctx, 'a>,
|
||||||
let rhs = params.get(1).unwrap();
|
// params: &[InstructionValue],
|
||||||
let div = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
|
// ) -> Result<StackValue, ErrorKind> {
|
||||||
let mul = scope.block.build(Instr::Mul(*rhs, div)).unwrap();
|
// let lhs = params.get(0).unwrap();
|
||||||
let sub = scope.block.build(Instr::Sub(*lhs, mul)).unwrap();
|
// let rhs = params.get(1).unwrap();
|
||||||
Ok(StackValue(StackValueKind::Literal(sub), self.0.clone()))
|
// let add = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
|
||||||
}
|
// Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[derive(Debug, Clone)]
|
||||||
|
// pub struct IntrinsicUMod(TypeKind);
|
||||||
|
|
||||||
|
// impl IntrinsicFunction for IntrinsicUMod {
|
||||||
|
// fn codegen<'ctx, 'a>(
|
||||||
|
// &self,
|
||||||
|
// scope: &mut Scope<'ctx, 'a>,
|
||||||
|
// params: &[InstructionValue],
|
||||||
|
// ) -> Result<StackValue, ErrorKind> {
|
||||||
|
// let lhs = params.get(0).unwrap();
|
||||||
|
// let rhs = params.get(1).unwrap();
|
||||||
|
// let div = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
|
||||||
|
// let mul = scope.block.build(Instr::Mul(*rhs, div)).unwrap();
|
||||||
|
// let sub = scope.block.build(Instr::Sub(*lhs, mul)).unwrap();
|
||||||
|
// Ok(StackValue(StackValueKind::Literal(sub), self.0.clone()))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
@ -160,9 +160,7 @@ impl<'ctx> StackBinopDefinition<'ctx> {
|
|||||||
self.return_ty.clone(),
|
self.return_ty.clone(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
StackBinopFunctionKind::Intrinsic(fun) => {
|
StackBinopFunctionKind::Intrinsic(fun) => fun.codegen(scope, &[&lhs, &rhs]),
|
||||||
fun.codegen(scope, &[lhs.instr(), rhs.instr()])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
//! - Debug Symbols
|
//! - Debug Symbols
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::{path::PathBuf, thread, time::Duration};
|
||||||
|
|
||||||
use ast::{
|
use ast::{
|
||||||
lexer::{self, FullToken, Token},
|
lexer::{self, FullToken, Token},
|
||||||
@ -51,6 +51,7 @@ use codegen::intrinsics::{form_intrinsic_binops, form_intrinsics};
|
|||||||
use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError};
|
use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError};
|
||||||
use mir::{
|
use mir::{
|
||||||
linker::LinkerPass,
|
linker::LinkerPass,
|
||||||
|
pass::BinopMap,
|
||||||
typecheck::{typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs},
|
typecheck::{typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs},
|
||||||
};
|
};
|
||||||
use reid_lib::{compile::CompileOutput, Context};
|
use reid_lib::{compile::CompileOutput, Context};
|
||||||
@ -128,8 +129,22 @@ pub fn perform_all_passes<'map>(
|
|||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
dbg!(&context);
|
dbg!(&context);
|
||||||
|
|
||||||
|
let mut binops = BinopMap::default();
|
||||||
for module in &mut context.modules {
|
for module in &mut context.modules {
|
||||||
for intrinsic in form_intrinsic_binops() {
|
for intrinsic in form_intrinsic_binops() {
|
||||||
|
binops
|
||||||
|
.set(
|
||||||
|
mir::pass::ScopeBinopKey {
|
||||||
|
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||||
|
operator: intrinsic.op,
|
||||||
|
},
|
||||||
|
mir::pass::ScopeBinopDef {
|
||||||
|
hands: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||||
|
operator: intrinsic.op,
|
||||||
|
return_ty: intrinsic.return_type.clone(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
module.1.binop_defs.insert(0, intrinsic);
|
module.1.binop_defs.insert(0, intrinsic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,7 +177,7 @@ pub fn perform_all_passes<'map>(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let refs = TypeRefs::default();
|
let refs = TypeRefs::with_binops(binops);
|
||||||
|
|
||||||
let state = context.pass(&mut TypeInference { refs: &refs })?;
|
let state = context.pass(&mut TypeInference { refs: &refs })?;
|
||||||
|
|
||||||
@ -174,6 +189,8 @@ pub fn perform_all_passes<'map>(
|
|||||||
println!("{}", &context);
|
println!("{}", &context);
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
dbg!(&state);
|
dbg!(&state);
|
||||||
|
dbg!("asd!");
|
||||||
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
|
||||||
if !state.errors.is_empty() {
|
if !state.errors.is_empty() {
|
||||||
return Err(ReidError::from_kind(
|
return Err(ReidError::from_kind(
|
||||||
|
@ -43,20 +43,6 @@ impl TypeKind {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn binop_type(
|
|
||||||
lhs: &TypeKind,
|
|
||||||
rhs: &TypeKind,
|
|
||||||
binop: &ScopeBinopDef,
|
|
||||||
) -> Option<(TypeKind, TypeKind, TypeKind)> {
|
|
||||||
let lhs_ty = lhs.narrow_into(&binop.hands.0);
|
|
||||||
let rhs_ty = rhs.narrow_into(&binop.hands.1);
|
|
||||||
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
|
|
||||||
Some((lhs_ty, rhs_ty, binop.return_ty.clone()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reverse of binop_type, where the given hint is the known required output
|
/// Reverse of binop_type, where the given hint is the known required output
|
||||||
/// type of the binop, and the output is the hint for the lhs/rhs type.
|
/// type of the binop, and the output is the hint for the lhs/rhs type.
|
||||||
pub fn simple_binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> {
|
pub fn simple_binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> {
|
||||||
|
@ -119,6 +119,10 @@ impl<Key: std::hash::Hash + Eq, T: Clone + std::fmt::Debug> Storage<Key, T> {
|
|||||||
pub fn find(&self, key: &Key) -> Option<(&Key, &T)> {
|
pub fn find(&self, key: &Key) -> Option<(&Key, &T)> {
|
||||||
self.0.iter().find(|(k, _)| *k == key)
|
self.0.iter().find(|(k, _)| *k == key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn filter(&self, key: &Key) -> Vec<(&Key, &T)> {
|
||||||
|
self.0.iter().filter(|(k, _)| *k == key).collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type BinopMap = Storage<ScopeBinopKey, ScopeBinopDef>;
|
pub type BinopMap = Storage<ScopeBinopKey, ScopeBinopDef>;
|
||||||
@ -195,8 +199,12 @@ impl PartialEq for ScopeBinopKey {
|
|||||||
if self.operator.is_commutative() != other.operator.is_commutative() {
|
if self.operator.is_commutative() != other.operator.is_commutative() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let operators_eq = self.params == other.params;
|
|
||||||
let swapped_ops_eq = (self.params.1.clone(), self.params.0.clone()) == other.params;
|
let operators_eq = self.params.0.narrow_into(&other.params.0).is_ok()
|
||||||
|
&& self.params.1.narrow_into(&other.params.1).is_ok();
|
||||||
|
let swapped_ops_eq = self.params.0.narrow_into(&other.params.1).is_ok()
|
||||||
|
&& self.params.1.narrow_into(&other.params.0).is_ok();
|
||||||
|
|
||||||
if self.operator.is_commutative() {
|
if self.operator.is_commutative() {
|
||||||
operators_eq || swapped_ops_eq
|
operators_eq || swapped_ops_eq
|
||||||
} else {
|
} else {
|
||||||
@ -226,27 +234,11 @@ pub struct ScopeBinopDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ScopeBinopDef {
|
impl ScopeBinopDef {
|
||||||
pub fn binop_hint_old(
|
pub fn narrow(&self, lhs: &TypeKind, rhs: &TypeKind) -> Option<(TypeKind, TypeKind, TypeKind)> {
|
||||||
&self,
|
|
||||||
lhs: &TypeKind,
|
|
||||||
rhs: &TypeKind,
|
|
||||||
ret_ty: &TypeKind,
|
|
||||||
) -> Option<(TypeKind, TypeKind)> {
|
|
||||||
ret_ty.narrow_into(&self.return_ty).ok()?;
|
|
||||||
let lhs_ty = lhs.narrow_into(&self.hands.0);
|
let lhs_ty = lhs.narrow_into(&self.hands.0);
|
||||||
let rhs_ty = rhs.narrow_into(&self.hands.1);
|
let rhs_ty = rhs.narrow_into(&self.hands.1);
|
||||||
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
|
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
|
||||||
Some((lhs_ty, rhs_ty))
|
Some((lhs_ty, rhs_ty, self.return_ty.clone()))
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn binop_ret_ty(&self, lhs: &TypeKind, rhs: &TypeKind) -> Option<TypeKind> {
|
|
||||||
let lhs_ty = lhs.narrow_into(&self.hands.0);
|
|
||||||
let rhs_ty = rhs.narrow_into(&self.hands.1);
|
|
||||||
if let (Ok(_), Ok(_)) = (lhs_ty, rhs_ty) {
|
|
||||||
Some(self.return_ty.clone())
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -453,73 +453,93 @@ impl Expression {
|
|||||||
let rhs_res = rhs.typecheck(state, &typerefs, None);
|
let rhs_res = rhs.typecheck(state, &typerefs, None);
|
||||||
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
|
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
|
||||||
|
|
||||||
let cloned = state.scope.binops.clone();
|
if let Some(binop) = state
|
||||||
let mut iter = cloned.iter();
|
.scope
|
||||||
let operator = loop {
|
.binops
|
||||||
let Some((_, binop)) = iter.next() else {
|
.find(&pass::ScopeBinopKey {
|
||||||
break None;
|
params: (lhs_type.clone(), rhs_type.clone()),
|
||||||
};
|
operator: *op,
|
||||||
if binop.operator != *op {
|
})
|
||||||
continue;
|
.map(|v| (v.1.clone()))
|
||||||
}
|
|
||||||
if let Some(hint_t) = hint_t {
|
|
||||||
if binop.return_ty == *hint_t {
|
|
||||||
if let Some(_) = TypeKind::binop_type(&lhs_type, &rhs_type, binop) {
|
|
||||||
break Some(binop);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(_) = TypeKind::binop_type(&lhs_type, &rhs_type, binop) {
|
|
||||||
break Some(binop);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(operator) = operator {
|
|
||||||
// Re-typecheck with found operator hints
|
|
||||||
let (lhs_ty, rhs_ty) = TypeKind::try_collapse_two(
|
|
||||||
(&lhs_type, &rhs_type),
|
|
||||||
(&operator.hands.0, &operator.hands.1),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let lhs_res = lhs.typecheck(state, &typerefs, Some(&lhs_ty));
|
|
||||||
let rhs_res = rhs.typecheck(state, &typerefs, Some(&rhs_ty));
|
|
||||||
state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
|
|
||||||
state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
|
|
||||||
Ok(operator.return_ty.clone())
|
|
||||||
} else {
|
|
||||||
// Re-typecheck with typical everyday binop
|
|
||||||
let lhs_res = lhs.typecheck(
|
|
||||||
state,
|
|
||||||
&typerefs,
|
|
||||||
hint_t.and_then(|t| t.simple_binop_hint(op)).as_ref(),
|
|
||||||
);
|
|
||||||
let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
|
|
||||||
let rhs_res = rhs.typecheck(state, &typerefs, Some(&lhs_type));
|
|
||||||
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
|
|
||||||
|
|
||||||
let both_t = lhs_type.narrow_into(&rhs_type)?;
|
|
||||||
|
|
||||||
if *op == BinaryOperator::Minus && !lhs_type.signed() {
|
|
||||||
if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value()?, rhs.num_value()?)
|
|
||||||
{
|
{
|
||||||
if lhs_val < rhs_val {
|
dbg!(&lhs, &rhs);
|
||||||
return Err(ErrorKind::NegativeUnsignedValue(lhs_type));
|
dbg!(&lhs_type.resolve_ref(typerefs));
|
||||||
}
|
dbg!(&rhs_type.resolve_ref(typerefs));
|
||||||
}
|
lhs.typecheck(state, &typerefs, Some(&binop.hands.0))?;
|
||||||
|
rhs.typecheck(state, &typerefs, Some(&binop.hands.1))?;
|
||||||
|
Ok(binop.narrow(&lhs_type, &rhs_type).unwrap().2)
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::InvalidBinop(*op, lhs_type, rhs_type))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(collapsed) = state.ok(rhs_type.narrow_into(&rhs_type), self.1) {
|
// let cloned = state.scope.binops.clone();
|
||||||
// Try to coerce both sides again with collapsed type
|
// let mut iter = cloned.iter();
|
||||||
lhs.typecheck(state, &typerefs, Some(&collapsed)).ok();
|
// let operator = loop {
|
||||||
rhs.typecheck(state, &typerefs, Some(&collapsed)).ok();
|
// let Some((_, binop)) = iter.next() else {
|
||||||
}
|
// break None;
|
||||||
|
// };
|
||||||
|
// if binop.operator != *op {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// if let Some(hint_t) = hint_t {
|
||||||
|
// if binop.return_ty == *hint_t {
|
||||||
|
// if let Some(_) = TypeKind::narrow_to_binop(&lhs_type, &rhs_type, binop)
|
||||||
|
// {
|
||||||
|
// break Some(binop);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if let Some(_) = TypeKind::narrow_to_binop(&lhs_type, &rhs_type, binop) {
|
||||||
|
// break Some(binop);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
both_t
|
// if let Some(operator) = operator {
|
||||||
.simple_binop_type(op)
|
// // Re-typecheck with found operator hints
|
||||||
.ok_or(ErrorKind::InvalidBinop(*op, lhs_type, rhs_type))
|
// let (lhs_ty, rhs_ty) = TypeKind::try_collapse_two(
|
||||||
}
|
// (&lhs_type, &rhs_type),
|
||||||
|
// (&operator.hands.0, &operator.hands.1),
|
||||||
|
// )
|
||||||
|
// .unwrap();
|
||||||
|
// let lhs_res = lhs.typecheck(state, &typerefs, Some(&lhs_ty));
|
||||||
|
// let rhs_res = rhs.typecheck(state, &typerefs, Some(&rhs_ty));
|
||||||
|
// state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
|
||||||
|
// state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
|
||||||
|
// Ok(operator.return_ty.clone())
|
||||||
|
// } else {
|
||||||
|
// // Re-typecheck with typical everyday binop
|
||||||
|
// let lhs_res = lhs.typecheck(
|
||||||
|
// state,
|
||||||
|
// &typerefs,
|
||||||
|
// hint_t.and_then(|t| t.simple_binop_hint(op)).as_ref(),
|
||||||
|
// );
|
||||||
|
// let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
|
||||||
|
// let rhs_res = rhs.typecheck(state, &typerefs, Some(&lhs_type));
|
||||||
|
// let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
|
||||||
|
|
||||||
|
// let both_t = lhs_type.narrow_into(&rhs_type)?;
|
||||||
|
|
||||||
|
// if *op == BinaryOperator::Minus && !lhs_type.signed() {
|
||||||
|
// if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value()?, rhs.num_value()?)
|
||||||
|
// {
|
||||||
|
// if lhs_val < rhs_val {
|
||||||
|
// return Err(ErrorKind::NegativeUnsignedValue(lhs_type));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if let Some(collapsed) = state.ok(rhs_type.narrow_into(&rhs_type), self.1) {
|
||||||
|
// // Try to coerce both sides again with collapsed type
|
||||||
|
// lhs.typecheck(state, &typerefs, Some(&collapsed)).ok();
|
||||||
|
// rhs.typecheck(state, &typerefs, Some(&collapsed)).ok();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// both_t
|
||||||
|
// .simple_binop_type(op)
|
||||||
|
// .ok_or(ErrorKind::InvalidBinop(*op, lhs_type, rhs_type))
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
ExprKind::FunctionCall(function_call) => {
|
ExprKind::FunctionCall(function_call) => {
|
||||||
let true_function = state
|
let true_function = state
|
||||||
@ -809,6 +829,7 @@ impl Literal {
|
|||||||
/// Try to coerce this literal, ie. convert it to a more specific type in
|
/// Try to coerce this literal, ie. convert it to a more specific type in
|
||||||
/// regards to the given hint if any.
|
/// regards to the given hint if any.
|
||||||
fn try_coerce(self, hint: Option<TypeKind>) -> Result<Self, ErrorKind> {
|
fn try_coerce(self, hint: Option<TypeKind>) -> Result<Self, ErrorKind> {
|
||||||
|
dbg!(&self, &hint);
|
||||||
if let Some(hint) = &hint {
|
if let Some(hint) = &hint {
|
||||||
use Literal as L;
|
use Literal as L;
|
||||||
use VagueLiteral as VagueL;
|
use VagueLiteral as VagueL;
|
||||||
|
@ -322,37 +322,25 @@ impl Expression {
|
|||||||
let mut lhs_ref = lhs.infer_types(state, type_refs)?;
|
let mut lhs_ref = lhs.infer_types(state, type_refs)?;
|
||||||
let mut rhs_ref = rhs.infer_types(state, type_refs)?;
|
let mut rhs_ref = rhs.infer_types(state, type_refs)?;
|
||||||
|
|
||||||
if let Ok(binop) = type_refs
|
let binops = type_refs.available_binops(op, &mut lhs_ref, &mut rhs_ref);
|
||||||
.binop(op, &mut lhs_ref, &mut rhs_ref, &state.scope.binops)
|
|
||||||
.ok_or(ErrorKind::TypesIncompatible(
|
if binops.len() > 0 {
|
||||||
|
let binop = unsafe { binops.get_unchecked(0) };
|
||||||
|
let mut widened_lhs = binop.hands.0.clone();
|
||||||
|
let mut widened_rhs = binop.hands.1.clone();
|
||||||
|
for binop in binops.iter().skip(1) {
|
||||||
|
widened_lhs = widened_lhs.widen_into(&binop.hands.0);
|
||||||
|
widened_rhs = widened_rhs.widen_into(&binop.hands.1);
|
||||||
|
}
|
||||||
|
lhs_ref.narrow(&type_refs.from_type(&widened_lhs).unwrap());
|
||||||
|
rhs_ref.narrow(&type_refs.from_type(&widened_rhs).unwrap());
|
||||||
|
Ok(type_refs.from_binop(*op, &lhs_ref, &rhs_ref))
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::InvalidBinop(
|
||||||
|
*op,
|
||||||
lhs_ref.resolve_deep().unwrap(),
|
lhs_ref.resolve_deep().unwrap(),
|
||||||
rhs_ref.resolve_deep().unwrap(),
|
rhs_ref.resolve_deep().unwrap(),
|
||||||
))
|
))
|
||||||
{
|
|
||||||
Ok(binop)
|
|
||||||
} else {
|
|
||||||
let typeref = state.or_else(
|
|
||||||
lhs_ref.narrow(&rhs_ref).ok_or(ErrorKind::InvalidBinop(
|
|
||||||
*op,
|
|
||||||
lhs_ref.resolve_deep().unwrap(),
|
|
||||||
rhs_ref.resolve_deep().unwrap(),
|
|
||||||
)),
|
|
||||||
type_refs.from_type(&Vague(Unknown)).unwrap(),
|
|
||||||
self.1,
|
|
||||||
);
|
|
||||||
Ok(type_refs
|
|
||||||
.from_type(
|
|
||||||
&typeref
|
|
||||||
.resolve_deep()
|
|
||||||
.unwrap()
|
|
||||||
.simple_binop_type(op)
|
|
||||||
.ok_or(ErrorKind::InvalidBinop(
|
|
||||||
*op,
|
|
||||||
lhs_ref.resolve_deep().unwrap(),
|
|
||||||
rhs_ref.resolve_deep().unwrap(),
|
|
||||||
))?,
|
|
||||||
)
|
|
||||||
.unwrap())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::FunctionCall(function_call) => {
|
ExprKind::FunctionCall(function_call) => {
|
||||||
|
@ -4,7 +4,10 @@ use std::{
|
|||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType};
|
use crate::{
|
||||||
|
ast::BinopDefinition,
|
||||||
|
mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
super::pass::{ScopeBinopDef, ScopeBinopKey, Storage},
|
super::pass::{ScopeBinopDef, ScopeBinopKey, Storage},
|
||||||
@ -64,33 +67,33 @@ pub enum TypeRefKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TypeRefKind {
|
impl TypeRefKind {
|
||||||
pub fn widen(&self, types: &TypeRefs) -> Option<TypeKind> {
|
pub fn widen(&self, types: &TypeRefs) -> TypeKind {
|
||||||
match self {
|
match self {
|
||||||
TypeRefKind::BinOp(op, lhs, rhs) => {
|
TypeRefKind::BinOp(op, lhs, rhs) => {
|
||||||
let mut binops = types
|
let mut binops = types
|
||||||
.binop_types
|
.binop_types
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|b| b.1.operator == *op)
|
.filter(|b| b.1.operator == *op)
|
||||||
.map(|b| b.1.binop_ret_ty(&lhs, &rhs))
|
.map(|b| b.1.narrow(&lhs, &rhs).map(|b| b.2))
|
||||||
.filter_map(|s| s);
|
.filter_map(|s| s);
|
||||||
if let Some(mut ty) = binops.next() {
|
if let Some(mut ty) = binops.next() {
|
||||||
while let Some(other) = binops.next() {
|
while let Some(other) = binops.next() {
|
||||||
ty = ty.widen_into(&other);
|
ty = ty.widen_into(&other);
|
||||||
}
|
}
|
||||||
Some(ty)
|
ty
|
||||||
} else {
|
} else {
|
||||||
None
|
TypeKind::Vague(VagueType::Unknown)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeRefKind::Direct(ty) => match ty {
|
TypeRefKind::Direct(ty) => match ty {
|
||||||
TypeKind::Vague(VagueType::TypeRef(id)) => types.retrieve_wide_type(*id),
|
TypeKind::Vague(VagueType::TypeRef(id)) => types.retrieve_wide_type(*id).unwrap(),
|
||||||
_ => Some(ty.clone()),
|
_ => ty.clone(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Default, Debug)]
|
||||||
pub struct TypeRefs {
|
pub struct TypeRefs {
|
||||||
/// Simple list of types that variables can refrence
|
/// Simple list of types that variables can refrence
|
||||||
pub(super) hints: RefCell<Vec<TypeRefKind>>,
|
pub(super) hints: RefCell<Vec<TypeRefKind>>,
|
||||||
@ -117,6 +120,14 @@ impl std::fmt::Display for TypeRefs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TypeRefs {
|
impl TypeRefs {
|
||||||
|
pub fn with_binops(binops: BinopMap) -> TypeRefs {
|
||||||
|
TypeRefs {
|
||||||
|
hints: Default::default(),
|
||||||
|
type_refs: Default::default(),
|
||||||
|
binop_types: binops,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(&self, ty: &TypeKind) -> TypeIdRef {
|
pub fn new(&self, ty: &TypeKind) -> TypeIdRef {
|
||||||
let idx = self.hints.borrow().len();
|
let idx = self.hints.borrow().len();
|
||||||
let typecell = Rc::new(RefCell::new(idx));
|
let typecell = Rc::new(RefCell::new(idx));
|
||||||
@ -127,6 +138,16 @@ impl TypeRefs {
|
|||||||
typecell
|
typecell
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn binop(&self, op: BinaryOperator, lhs: &TypeRef, rhs: &TypeRef) -> TypeIdRef {
|
||||||
|
let idx = self.hints.borrow().len();
|
||||||
|
let typecell = Rc::new(RefCell::new(idx));
|
||||||
|
self.type_refs.borrow_mut().push(typecell.clone());
|
||||||
|
self.hints
|
||||||
|
.borrow_mut()
|
||||||
|
.push(TypeRefKind::BinOp(op, lhs.as_type(), rhs.as_type()));
|
||||||
|
typecell
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find(&self, ty: &TypeKind) -> Option<TypeIdRef> {
|
pub fn find(&self, ty: &TypeKind) -> Option<TypeIdRef> {
|
||||||
if ty.known().is_err() {
|
if ty.known().is_err() {
|
||||||
// Only do this for non-vague types that can not be further narrowed
|
// Only do this for non-vague types that can not be further narrowed
|
||||||
@ -167,7 +188,6 @@ impl TypeRefs {
|
|||||||
.get(inner_idx)
|
.get(inner_idx)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|t| t.widen(self))
|
.map(|t| t.widen(self))
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,6 +252,15 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
|||||||
Some(TypeRef(idx, self))
|
Some(TypeRef(idx, self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_binop(
|
||||||
|
&'outer self,
|
||||||
|
op: BinaryOperator,
|
||||||
|
lhs: &TypeRef,
|
||||||
|
rhs: &TypeRef,
|
||||||
|
) -> TypeRef<'outer> {
|
||||||
|
TypeRef(self.types.binop(op, lhs, rhs), self)
|
||||||
|
}
|
||||||
|
|
||||||
fn narrow_to_type(&'outer self, hint: &TypeRef, ty: &TypeKind) -> Option<TypeRef<'outer>> {
|
fn narrow_to_type(&'outer self, hint: &TypeRef, ty: &TypeKind) -> Option<TypeRef<'outer>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut hints = self.types.hints.borrow_mut();
|
let mut hints = self.types.hints.borrow_mut();
|
||||||
@ -269,8 +298,7 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
|||||||
.borrow()
|
.borrow()
|
||||||
.get_unchecked(*hint2.0.borrow())
|
.get_unchecked(*hint2.0.borrow())
|
||||||
.clone()
|
.clone()
|
||||||
.widen(self.types)
|
.widen(self.types);
|
||||||
.unwrap();
|
|
||||||
self.narrow_to_type(&hint1, &ty)?;
|
self.narrow_to_type(&hint1, &ty)?;
|
||||||
for idx in self.types.type_refs.borrow_mut().iter_mut() {
|
for idx in self.types.type_refs.borrow_mut().iter_mut() {
|
||||||
if *idx == hint2.0 && idx != &hint1.0 {
|
if *idx == hint2.0 && idx != &hint1.0 {
|
||||||
@ -297,47 +325,36 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
|||||||
.or(self.outer.map(|o| o.find_var(name)).flatten())
|
.or(self.outer.map(|o| o.find_var(name)).flatten())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn binop(
|
pub fn available_binops(
|
||||||
&'outer self,
|
&'outer self,
|
||||||
op: &BinaryOperator,
|
op: &BinaryOperator,
|
||||||
lhs: &mut TypeRef<'outer>,
|
lhs: &mut TypeRef<'outer>,
|
||||||
rhs: &mut TypeRef<'outer>,
|
rhs: &mut TypeRef<'outer>,
|
||||||
binops: &Storage<ScopeBinopKey, ScopeBinopDef>,
|
) -> Vec<ScopeBinopDef> {
|
||||||
) -> Option<TypeRef<'outer>> {
|
let mut applying_binops = Vec::new();
|
||||||
if lhs.resolve_deep().unwrap().known().is_err()
|
for (_, binop) in self.types.binop_types.iter() {
|
||||||
&& rhs.resolve_deep().unwrap().known().is_err()
|
|
||||||
{
|
|
||||||
return self.from_type(&TypeKind::Vague(VagueType::Unknown));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut iter = binops.iter();
|
|
||||||
loop {
|
|
||||||
let Some((_, binop)) = iter.next() else {
|
|
||||||
break None;
|
|
||||||
};
|
|
||||||
if binop.operator != *op {
|
if binop.operator != *op {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(ret) = try_binop(lhs, rhs, binop) {
|
if let Some(_) = check_binop(lhs, rhs, binop) {
|
||||||
break Some(ret);
|
applying_binops.push(binop.clone());
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if binop.operator.is_commutative() {
|
if binop.operator.is_commutative() {
|
||||||
if let Some(ret) = try_binop(rhs, lhs, binop) {
|
if let Some(_) = check_binop(lhs, rhs, binop) {
|
||||||
return Some(ret);
|
applying_binops.push(binop.clone());
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
applying_binops
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_binop<'o>(
|
fn check_binop<'o>(
|
||||||
lhs: &mut TypeRef<'o>,
|
lhs: &mut TypeRef<'o>,
|
||||||
rhs: &mut TypeRef<'o>,
|
rhs: &mut TypeRef<'o>,
|
||||||
binop: &ScopeBinopDef,
|
binop: &ScopeBinopDef,
|
||||||
) -> Option<TypeRef<'o>> {
|
) -> Option<(TypeKind, TypeKind, TypeKind)> {
|
||||||
let (lhs_ty, rhs_ty, ret_ty) =
|
binop.narrow(&lhs.resolve_deep()?, &rhs.resolve_deep()?)
|
||||||
TypeKind::binop_type(&lhs.resolve_deep()?, &rhs.resolve_deep()?, binop)?;
|
|
||||||
lhs.narrow(&lhs.1.from_type(&lhs_ty).unwrap()).unwrap();
|
|
||||||
rhs.narrow(&rhs.1.from_type(&rhs_ty).unwrap()).unwrap();
|
|
||||||
lhs.1.from_type(&ret_ty)
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user