Add operator to scopebinop, add some typechecking for binops

This commit is contained in:
Sofia 2025-07-24 15:09:27 +03:00
parent aec7d55e9b
commit 9f7022b4c0
6 changed files with 55 additions and 27 deletions

View File

@ -400,8 +400,9 @@ impl mir::Module {
binops.insert( binops.insert(
ScopeBinopKey { ScopeBinopKey {
operators: (binop.lhs.1.clone(), binop.rhs.1.clone()), params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
commutative: mir::pass::CommutativeKind::True, commutative: mir::pass::CommutativeKind::True,
operator: binop.op,
}, },
StackBinopDefinition { StackBinopDefinition {
parameters: (binop.lhs.clone(), binop.rhs.clone()), parameters: (binop.lhs.clone(), binop.rhs.clone()),

View File

@ -110,13 +110,13 @@ impl TypeKind {
} }
} }
pub fn binop_type<'o>( pub fn binop_type(
lhs: &TypeKind, lhs: &TypeKind,
rhs: &TypeKind, rhs: &TypeKind,
binop: &ScopeBinopDef, binop: &ScopeBinopDef,
) -> Option<(TypeKind, TypeKind, TypeKind)> { ) -> Option<(TypeKind, TypeKind, TypeKind)> {
let lhs_ty = lhs.collapse_into(&binop.operators.0); let lhs_ty = lhs.collapse_into(&binop.hands.0);
let rhs_ty = rhs.collapse_into(&binop.operators.1); let rhs_ty = rhs.collapse_into(&binop.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, binop.return_ty.clone())) Some((lhs_ty, rhs_ty, binop.return_ty.clone()))
} else { } else {
@ -126,7 +126,7 @@ impl TypeKind {
/// 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 binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> { pub fn simple_binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> {
match op { match op {
BinaryOperator::Add BinaryOperator::Add
| BinaryOperator::Minus | BinaryOperator::Minus
@ -138,6 +138,22 @@ impl TypeKind {
} }
} }
pub fn binop_hint(
&self,
lhs: &TypeKind,
rhs: &TypeKind,
binop: &ScopeBinopDef,
) -> Option<(TypeKind, TypeKind)> {
self.collapse_into(&binop.return_ty).ok()?;
let lhs_ty = lhs.collapse_into(&binop.hands.0);
let rhs_ty = rhs.collapse_into(&binop.hands.1);
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
Some((lhs_ty, rhs_ty))
} else {
None
}
}
pub fn signed(&self) -> bool { pub fn signed(&self) -> bool {
match self { match self {
TypeKind::Bool => false, TypeKind::Bool => false,

View File

@ -214,7 +214,7 @@ impl VagueLiteral {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum BinaryOperator { pub enum BinaryOperator {
Add, Add,
Minus, Minus,
@ -226,7 +226,7 @@ pub enum BinaryOperator {
} }
/// Specifically the operators that LLVM likes to take in as "icmp" parameters /// Specifically the operators that LLVM likes to take in as "icmp" parameters
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CmpOperator { pub enum CmpOperator {
LT, LT,
LE, LE,

View File

@ -170,7 +170,8 @@ pub struct ScopeVariable {
#[derive(Clone, Debug, Eq)] #[derive(Clone, Debug, Eq)]
pub struct ScopeBinopKey { pub struct ScopeBinopKey {
pub operators: (TypeKind, TypeKind), pub params: (TypeKind, TypeKind),
pub operator: BinaryOperator,
pub commutative: CommutativeKind, pub commutative: CommutativeKind,
} }
@ -183,14 +184,16 @@ pub enum CommutativeKind {
impl PartialEq for ScopeBinopKey { impl PartialEq for ScopeBinopKey {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
if self.operator != other.operator {
return false;
}
if self.commutative != CommutativeKind::Any && other.commutative != CommutativeKind::Any { if self.commutative != CommutativeKind::Any && other.commutative != CommutativeKind::Any {
if self.commutative != other.commutative { if self.commutative != other.commutative {
return false; return false;
} }
} }
let operators_eq = self.operators == other.operators; let operators_eq = self.params == other.params;
let swapped_ops_eq = let swapped_ops_eq = (self.params.1.clone(), self.params.0.clone()) == other.params;
(self.operators.1.clone(), self.operators.0.clone()) == other.operators;
if self.commutative == CommutativeKind::True || other.commutative == CommutativeKind::True { if self.commutative == CommutativeKind::True || other.commutative == CommutativeKind::True {
operators_eq || swapped_ops_eq operators_eq || swapped_ops_eq
} else { } else {
@ -202,18 +205,20 @@ impl PartialEq for ScopeBinopKey {
impl std::hash::Hash for ScopeBinopKey { impl std::hash::Hash for ScopeBinopKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
if self.commutative == CommutativeKind::True { if self.commutative == CommutativeKind::True {
let mut sorted = vec![&self.operators.0, &self.operators.1]; let mut sorted = vec![&self.params.0, &self.params.1];
sorted.sort(); sorted.sort();
sorted.hash(state); sorted.hash(state);
self.operator.hash(state);
} else { } else {
self.operators.hash(state); self.params.hash(state);
} }
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ScopeBinopDef { pub struct ScopeBinopDef {
pub operators: (TypeKind, TypeKind), pub hands: (TypeKind, TypeKind),
pub operator: BinaryOperator,
pub commutative: bool, pub commutative: bool,
pub return_ty: TypeKind, pub return_ty: TypeKind,
} }
@ -358,17 +363,22 @@ impl Module {
} }
for binop in &self.binop_defs { for binop in &self.binop_defs {
scope.binops.set( scope
ScopeBinopKey { .binops
operators: (binop.lhs.1.clone(), binop.rhs.1.clone()), .set(
commutative: CommutativeKind::True, ScopeBinopKey {
}, params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
ScopeBinopDef { commutative: CommutativeKind::True,
operators: (binop.lhs.1.clone(), binop.rhs.1.clone()), operator: binop.op,
commutative: true, },
return_ty: binop.return_type.clone(), ScopeBinopDef {
}, hands: (binop.lhs.1.clone(), binop.rhs.1.clone()),
); operator: binop.op,
commutative: true,
return_ty: binop.return_type.clone(),
},
)
.ok();
} }
for function in &self.functions { for function in &self.functions {

View File

@ -513,7 +513,7 @@ impl Expression {
let lhs_res = lhs.typecheck( let lhs_res = lhs.typecheck(
state, state,
&typerefs, &typerefs,
hint_t.and_then(|t| t.binop_hint(op)).as_ref(), 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 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_res = rhs.typecheck(state, &typerefs, Some(&lhs_type));

View File

@ -62,8 +62,9 @@ impl<'t> Pass for TypeInference<'t> {
let mut seen_binops = HashSet::new(); let mut seen_binops = HashSet::new();
for binop in &module.binop_defs { for binop in &module.binop_defs {
let binop_key = ScopeBinopKey { let binop_key = ScopeBinopKey {
operators: (binop.lhs.1.clone(), binop.rhs.1.clone()), params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
commutative: pass::CommutativeKind::True, commutative: pass::CommutativeKind::True,
operator: binop.op,
}; };
if seen_binops.contains(&binop_key) { if seen_binops.contains(&binop_key) {
state.note_errors( state.note_errors(