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 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<FunctionDefinition> { | ||||
| pub fn form_intrinsic_binops() -> Vec<BinopDefinition> { | ||||
|     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<StackValue, ErrorKind>; | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct IntrinsicIAdd(TypeKind); | ||||
| #[derive(Clone)] | ||||
| pub struct IntrinsicSimpleInstr<T>(T) | ||||
| where | ||||
|     T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue; | ||||
| 
 | ||||
| impl IntrinsicFunction for IntrinsicIAdd { | ||||
|     fn codegen<'ctx, 'a>( | ||||
| impl<T> std::fmt::Debug for IntrinsicSimpleInstr<T> | ||||
| 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, | ||||
|         scope: &mut Scope<'ctx, 'a>, | ||||
|         params: &[InstructionValue], | ||||
|         scope: &mut Scope<'b, 'c>, | ||||
|         params: &[&StackValue], | ||||
|     ) -> 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())) | ||||
|         let instr = self.clone().0(scope, lhs.instr(), rhs.instr()); | ||||
|         Ok(StackValue(StackValueKind::Literal(instr), lhs.1.clone())) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct IntrinsicUDiv(TypeKind); | ||||
| // impl IntrinsicFunction for IntrinsicIAdd {
 | ||||
| //     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 { | ||||
|     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::UDiv(*lhs, *rhs)).unwrap(); | ||||
|         Ok(StackValue(StackValueKind::Literal(add), self.0.clone())) | ||||
|     } | ||||
| } | ||||
| // #[derive(Debug, Clone)]
 | ||||
| // pub struct IntrinsicIAdd(TypeKind);
 | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct IntrinsicUMod(TypeKind); | ||||
| // impl IntrinsicFunction for IntrinsicIAdd {
 | ||||
| //     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 { | ||||
|     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())) | ||||
|     } | ||||
| } | ||||
| // #[derive(Debug, Clone)]
 | ||||
| // pub struct IntrinsicUDiv(TypeKind);
 | ||||
| 
 | ||||
| // impl IntrinsicFunction for IntrinsicUDiv {
 | ||||
| //     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::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(), | ||||
|                 )) | ||||
|             } | ||||
|             StackBinopFunctionKind::Intrinsic(fun) => { | ||||
|                 fun.codegen(scope, &[lhs.instr(), rhs.instr()]) | ||||
|             } | ||||
|             StackBinopFunctionKind::Intrinsic(fun) => fun.codegen(scope, &[&lhs, &rhs]), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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( | ||||
|  | ||||
| @ -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<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)> { | ||||
|         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>; | ||||
| @ -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<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()) | ||||
|             Some((lhs_ty, rhs_ty, self.return_ty.clone())) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|  | ||||
| @ -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()) | ||||
|                 } 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 let Some(binop) = state | ||||
|                     .scope | ||||
|                     .binops | ||||
|                     .find(&pass::ScopeBinopKey { | ||||
|                         params: (lhs_type.clone(), rhs_type.clone()), | ||||
|                         operator: *op, | ||||
|                     }) | ||||
|                     .map(|v| (v.1.clone())) | ||||
|                 { | ||||
|                             if lhs_val < rhs_val { | ||||
|                                 return Err(ErrorKind::NegativeUnsignedValue(lhs_type)); | ||||
|                             } | ||||
|                         } | ||||
|                     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 { | ||||
|                     Err(ErrorKind::InvalidBinop(*op, lhs_type, rhs_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(); | ||||
|                     } | ||||
|                 // 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);
 | ||||
|                 //     }
 | ||||
|                 // };
 | ||||
| 
 | ||||
|                     both_t | ||||
|                         .simple_binop_type(op) | ||||
|                         .ok_or(ErrorKind::InvalidBinop(*op, lhs_type, rhs_type)) | ||||
|                 } | ||||
|                 // 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<TypeKind>) -> Result<Self, ErrorKind> { | ||||
|         dbg!(&self, &hint); | ||||
|         if let Some(hint) = &hint { | ||||
|             use Literal as L; | ||||
|             use VagueLiteral as VagueL; | ||||
|  | ||||
| @ -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) => { | ||||
|  | ||||
| @ -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<TypeKind> { | ||||
|     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<Vec<TypeRefKind>>, | ||||
| @ -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<TypeIdRef> { | ||||
|         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<TypeRef<'outer>> { | ||||
|         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<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)); | ||||
|         } | ||||
| 
 | ||||
|         let mut iter = binops.iter(); | ||||
|         loop { | ||||
|             let Some((_, binop)) = iter.next() else { | ||||
|                 break None; | ||||
|             }; | ||||
|     ) -> Vec<ScopeBinopDef> { | ||||
|         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<TypeRef<'o>> { | ||||
|     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()?) | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user