Possibly fix typechecking for binops

This commit is contained in:
Sofia 2025-07-24 18:42:10 +03:00
parent 8810d34d54
commit 27db67dd99
6 changed files with 36 additions and 14 deletions

View File

@ -21,5 +21,5 @@ fn main() -> u8 {
free_string(&test);
return addition(5, 3);
return 8;
}

View File

@ -314,7 +314,7 @@ fn parse_binop_rhs(
lhs = Expression(
ExpressionKind::Binop(op, Box::new(lhs), Box::new(rhs)),
stream.get_range().unwrap(),
stream.get_range_prev().unwrap(),
);
}

View File

@ -115,6 +115,10 @@ impl<Key: std::hash::Hash + Eq, T: Clone + std::fmt::Debug> Storage<Key, T> {
pub fn iter(&self) -> impl Iterator<Item = (&Key, &T)> {
self.0.iter()
}
pub fn find(&self, key: &Key) -> Option<(&Key, &T)> {
self.0.iter().find(|(k, _)| *k == key)
}
}
#[derive(Clone, Default, Debug)]
@ -216,7 +220,6 @@ impl std::hash::Hash for ScopeBinopKey {
pub struct ScopeBinopDef {
pub hands: (TypeKind, TypeKind),
pub operator: BinaryOperator,
pub commutative: bool,
pub return_ty: TypeKind,
}
@ -370,7 +373,6 @@ impl Module {
ScopeBinopDef {
hands: (binop.lhs.1.clone(), binop.rhs.1.clone()),
operator: binop.op,
commutative: true,
return_ty: binop.return_type.clone(),
},
)

View File

@ -514,14 +514,28 @@ impl Expression {
let rhs_res = rhs.typecheck(state, &typerefs, None);
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
let operator = state
.scope
.binops
.get(&pass::ScopeBinopKey {
params: (lhs_type.clone(), rhs_type.clone()),
operator: *op,
})
.cloned();
let cloned = state.scope.binops.clone();
let mut iter = cloned.iter();
let operator = loop {
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::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
@ -534,7 +548,7 @@ impl Expression {
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)
Ok(operator.return_ty.clone())
} else {
// Re-typecheck with typical everyday binop
let lhs_res = lhs.typecheck(

View File

@ -311,6 +311,7 @@ impl Expression {
// Infer LHS and RHS, and return binop type
let mut lhs_ref = lhs.infer_types(state, type_refs)?;
let mut rhs_ref = rhs.infer_types(state, type_refs)?;
type_refs
.binop(op, &mut lhs_ref, &mut rhs_ref, &state.scope.binops)
.ok_or(ErrorKind::TypesIncompatible(

View File

@ -233,11 +233,16 @@ impl<'outer> ScopeTypeRefs<'outer> {
rhs: &mut TypeRef<'outer>,
binops: &Storage<ScopeBinopKey, ScopeBinopDef>,
) -> Option<TypeRef<'outer>> {
if lhs.resolve_deep().unwrap().known().is_err()
&& rhs.resolve_deep().unwrap().known().is_err()
{
return self.from_type(&TypeKind::Vague(VagueType::Unknown));
}
for (_, binop) in binops.iter() {
if let Some(ret) = try_binop(lhs, rhs, binop) {
return Some(ret);
}
if binop.commutative {
if binop.operator.is_commutative() {
if let Some(ret) = try_binop(rhs, lhs, binop) {
return Some(ret);
}