diff --git a/reid/src/codegen/intrinsics.rs b/reid/src/codegen/intrinsics.rs index 99c5cea..130f68d 100644 --- a/reid/src/codegen/intrinsics.rs +++ b/reid/src/codegen/intrinsics.rs @@ -1,8 +1,10 @@ +use std::marker::PhantomData; + use reid_lib::{builder::InstructionValue, Instr}; use crate::{ codegen::{ErrorKind, StackValueKind}, - mir::{BinopDefinition, FunctionDefinition, TypeKind}, + mir::{BinaryOperator, BinopDefinition, FunctionDefinition, FunctionDefinitionKind, TypeKind}, }; use super::scope::{Scope, StackValue}; @@ -16,6 +18,72 @@ pub fn form_intrinsics() -> Vec { pub fn form_intrinsic_binops() -> Vec { 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 } @@ -23,56 +91,99 @@ pub trait IntrinsicFunction: std::fmt::Debug { fn codegen<'ctx, 'a>( &self, scope: &mut Scope<'ctx, 'a>, - params: &[InstructionValue], + params: &[&StackValue], ) -> Result; } -#[derive(Debug, Clone)] -pub struct IntrinsicIAdd(TypeKind); +#[derive(Clone)] +pub struct IntrinsicSimpleInstr(T) +where + T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue; -impl IntrinsicFunction for IntrinsicIAdd { - fn codegen<'ctx, 'a>( - &self, - scope: &mut Scope<'ctx, 'a>, - params: &[InstructionValue], - ) -> Result { - 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 std::fmt::Debug for IntrinsicSimpleInstr +where + T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("IntrinsicSimpleInstr").finish() } } -#[derive(Debug, Clone)] -pub struct IntrinsicUDiv(TypeKind); - -impl IntrinsicFunction for IntrinsicUDiv { - fn codegen<'ctx, 'a>( +impl IntrinsicFunction for IntrinsicSimpleInstr +where + T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, +{ + fn codegen<'b, 'c>( &self, - scope: &mut Scope<'ctx, 'a>, - params: &[InstructionValue], + scope: &mut Scope<'b, 'c>, + params: &[&StackValue], ) -> Result { 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())) + let instr = self.clone().0(scope, lhs.instr(), rhs.instr()); + Ok(StackValue(StackValueKind::Literal(instr), lhs.1.clone())) } } -#[derive(Debug, Clone)] -pub struct IntrinsicUMod(TypeKind); +// impl IntrinsicFunction for IntrinsicIAdd { +// fn codegen<'ctx, 'a>( +// &self, +// scope: &mut Scope<'ctx, 'a>, +// params: &[InstructionValue], +// ) -> Result { +// 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 { - fn codegen<'ctx, 'a>( - &self, - scope: &mut Scope<'ctx, 'a>, - params: &[InstructionValue], - ) -> Result { - 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())) - } -} +// #[derive(Debug, Clone)] +// pub struct IntrinsicIAdd(TypeKind); + +// impl IntrinsicFunction for IntrinsicIAdd { +// fn codegen<'ctx, 'a>( +// &self, +// scope: &mut Scope<'ctx, 'a>, +// params: &[InstructionValue], +// ) -> Result { +// 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())) +// } +// } + +// #[derive(Debug, Clone)] +// pub struct IntrinsicUDiv(TypeKind); + +// impl IntrinsicFunction for IntrinsicUDiv { +// fn codegen<'ctx, 'a>( +// &self, +// scope: &mut Scope<'ctx, 'a>, +// params: &[InstructionValue], +// ) -> Result { +// 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)] +// pub struct IntrinsicUMod(TypeKind); + +// impl IntrinsicFunction for IntrinsicUMod { +// fn codegen<'ctx, 'a>( +// &self, +// scope: &mut Scope<'ctx, 'a>, +// params: &[InstructionValue], +// ) -> Result { +// 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())) +// } +// } diff --git a/reid/src/codegen/scope.rs b/reid/src/codegen/scope.rs index 5121a8f..1232ae2 100644 --- a/reid/src/codegen/scope.rs +++ b/reid/src/codegen/scope.rs @@ -160,9 +160,7 @@ impl<'ctx> StackBinopDefinition<'ctx> { self.return_ty.clone(), )) } - StackBinopFunctionKind::Intrinsic(fun) => { - fun.codegen(scope, &[lhs.instr(), rhs.instr()]) - } + StackBinopFunctionKind::Intrinsic(fun) => fun.codegen(scope, &[&lhs, &rhs]), } } } diff --git a/reid/src/lib.rs b/reid/src/lib.rs index 9c58b59..42c024b 100644 --- a/reid/src/lib.rs +++ b/reid/src/lib.rs @@ -41,7 +41,7 @@ //! - Debug Symbols //! ``` -use std::path::PathBuf; +use std::{path::PathBuf, thread, time::Duration}; use ast::{ 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 mir::{ linker::LinkerPass, + pass::BinopMap, typecheck::{typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs}, }; use reid_lib::{compile::CompileOutput, Context}; @@ -128,8 +129,22 @@ pub fn perform_all_passes<'map>( #[cfg(debug_assertions)] dbg!(&context); + let mut binops = BinopMap::default(); for module in &mut context.modules { 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); } } @@ -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 })?; @@ -174,6 +189,8 @@ pub fn perform_all_passes<'map>( println!("{}", &context); #[cfg(debug_assertions)] dbg!(&state); + dbg!("asd!"); + thread::sleep(Duration::from_millis(100)); if !state.errors.is_empty() { return Err(ReidError::from_kind( diff --git a/reid/src/mir/implement.rs b/reid/src/mir/implement.rs index f3367ed..0168d22 100644 --- a/reid/src/mir/implement.rs +++ b/reid/src/mir/implement.rs @@ -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 /// type of the binop, and the output is the hint for the lhs/rhs type. pub fn simple_binop_hint(&self, op: &BinaryOperator) -> Option { diff --git a/reid/src/mir/pass.rs b/reid/src/mir/pass.rs index 293f376..69537a8 100644 --- a/reid/src/mir/pass.rs +++ b/reid/src/mir/pass.rs @@ -119,6 +119,10 @@ impl Storage { pub fn find(&self, key: &Key) -> Option<(&Key, &T)> { 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; @@ -195,8 +199,12 @@ impl PartialEq for ScopeBinopKey { if self.operator.is_commutative() != other.operator.is_commutative() { 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() { operators_eq || swapped_ops_eq } else { @@ -226,27 +234,11 @@ pub struct ScopeBinopDef { } impl ScopeBinopDef { - pub fn binop_hint_old( - &self, - lhs: &TypeKind, - rhs: &TypeKind, - ret_ty: &TypeKind, - ) -> Option<(TypeKind, TypeKind)> { - ret_ty.narrow_into(&self.return_ty).ok()?; + pub fn narrow(&self, lhs: &TypeKind, rhs: &TypeKind) -> Option<(TypeKind, TypeKind, TypeKind)> { let lhs_ty = lhs.narrow_into(&self.hands.0); let rhs_ty = rhs.narrow_into(&self.hands.1); if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) { - Some((lhs_ty, rhs_ty)) - } else { - None - } - } - - pub fn binop_ret_ty(&self, lhs: &TypeKind, rhs: &TypeKind) -> Option { - 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()) + Some((lhs_ty, rhs_ty, self.return_ty.clone())) } else { None } diff --git a/reid/src/mir/typecheck/typecheck.rs b/reid/src/mir/typecheck/typecheck.rs index 090bde6..e1c2c24 100644 --- a/reid/src/mir/typecheck/typecheck.rs +++ b/reid/src/mir/typecheck/typecheck.rs @@ -453,73 +453,93 @@ 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 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 - 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()) + if let Some(binop) = state + .scope + .binops + .find(&pass::ScopeBinopKey { + params: (lhs_type.clone(), rhs_type.clone()), + operator: *op, + }) + .map(|v| (v.1.clone())) + { + dbg!(&lhs, &rhs); + 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 { - // 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)) + Err(ErrorKind::InvalidBinop(*op, lhs_type, rhs_type)) } + + // 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::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); + // } + // }; + + // 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 { + // 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) => { let true_function = state @@ -809,6 +829,7 @@ impl Literal { /// Try to coerce this literal, ie. convert it to a more specific type in /// regards to the given hint if any. fn try_coerce(self, hint: Option) -> Result { + dbg!(&self, &hint); if let Some(hint) = &hint { use Literal as L; use VagueLiteral as VagueL; diff --git a/reid/src/mir/typecheck/typeinference.rs b/reid/src/mir/typecheck/typeinference.rs index c87aa95..4a04a59 100644 --- a/reid/src/mir/typecheck/typeinference.rs +++ b/reid/src/mir/typecheck/typeinference.rs @@ -322,37 +322,25 @@ impl Expression { let mut lhs_ref = lhs.infer_types(state, type_refs)?; let mut rhs_ref = rhs.infer_types(state, type_refs)?; - if let Ok(binop) = type_refs - .binop(op, &mut lhs_ref, &mut rhs_ref, &state.scope.binops) - .ok_or(ErrorKind::TypesIncompatible( + let binops = type_refs.available_binops(op, &mut lhs_ref, &mut rhs_ref); + + 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(), 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) => { diff --git a/reid/src/mir/typecheck/typerefs.rs b/reid/src/mir/typecheck/typerefs.rs index affd176..c06538a 100644 --- a/reid/src/mir/typecheck/typerefs.rs +++ b/reid/src/mir/typecheck/typerefs.rs @@ -4,7 +4,10 @@ use std::{ rc::Rc, }; -use crate::mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType}; +use crate::{ + ast::BinopDefinition, + mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType}, +}; use super::{ super::pass::{ScopeBinopDef, ScopeBinopKey, Storage}, @@ -64,33 +67,33 @@ pub enum TypeRefKind { } impl TypeRefKind { - pub fn widen(&self, types: &TypeRefs) -> Option { + pub fn widen(&self, types: &TypeRefs) -> TypeKind { match self { TypeRefKind::BinOp(op, lhs, rhs) => { let mut binops = types .binop_types .iter() .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); if let Some(mut ty) = binops.next() { while let Some(other) = binops.next() { ty = ty.widen_into(&other); } - Some(ty) + ty } else { - None + TypeKind::Vague(VagueType::Unknown) } } TypeRefKind::Direct(ty) => match ty { - TypeKind::Vague(VagueType::TypeRef(id)) => types.retrieve_wide_type(*id), - _ => Some(ty.clone()), + TypeKind::Vague(VagueType::TypeRef(id)) => types.retrieve_wide_type(*id).unwrap(), + _ => ty.clone(), }, } } } -#[derive(Debug, Default)] +#[derive(Default, Debug)] pub struct TypeRefs { /// Simple list of types that variables can refrence pub(super) hints: RefCell>, @@ -117,6 +120,14 @@ impl std::fmt::Display for 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 { let idx = self.hints.borrow().len(); let typecell = Rc::new(RefCell::new(idx)); @@ -127,6 +138,16 @@ impl TypeRefs { 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 { if ty.known().is_err() { // Only do this for non-vague types that can not be further narrowed @@ -167,7 +188,6 @@ impl TypeRefs { .get(inner_idx) .cloned() .map(|t| t.widen(self)) - .flatten() } } @@ -232,6 +252,15 @@ impl<'outer> ScopeTypeRefs<'outer> { 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> { unsafe { let mut hints = self.types.hints.borrow_mut(); @@ -269,8 +298,7 @@ impl<'outer> ScopeTypeRefs<'outer> { .borrow() .get_unchecked(*hint2.0.borrow()) .clone() - .widen(self.types) - .unwrap(); + .widen(self.types); self.narrow_to_type(&hint1, &ty)?; for idx in self.types.type_refs.borrow_mut().iter_mut() { 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()) } - pub fn binop( + pub fn available_binops( &'outer self, op: &BinaryOperator, lhs: &mut TypeRef<'outer>, rhs: &mut TypeRef<'outer>, - binops: &Storage, - ) -> Option> { - if lhs.resolve_deep().unwrap().known().is_err() - && 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; - }; + ) -> Vec { + let mut applying_binops = Vec::new(); + for (_, binop) in self.types.binop_types.iter() { if binop.operator != *op { continue; } - if let Some(ret) = try_binop(lhs, rhs, binop) { - break Some(ret); + if let Some(_) = check_binop(lhs, rhs, binop) { + applying_binops.push(binop.clone()); + continue; } if binop.operator.is_commutative() { - if let Some(ret) = try_binop(rhs, lhs, binop) { - return Some(ret); + if let Some(_) = check_binop(lhs, rhs, binop) { + applying_binops.push(binop.clone()); + continue; } } } + applying_binops } } -fn try_binop<'o>( +fn check_binop<'o>( lhs: &mut TypeRef<'o>, rhs: &mut TypeRef<'o>, binop: &ScopeBinopDef, -) -> Option> { - let (lhs_ty, rhs_ty, ret_ty) = - 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) +) -> Option<(TypeKind, TypeKind, TypeKind)> { + binop.narrow(&lhs.resolve_deep()?, &rhs.resolve_deep()?) }